2014-10-04 90 views
1

我正在尝试做一个GET请求,然后将我得到的内容发送到POST请求中的另一个站点。下面的代码工作正常:发送两个功能之间的`阅读器'

func deliver(sourceURL *url.URL, destinationURL *url.URL) { 
    client := &http.Client{} 
    sourceResponse, err := http.Get(sourceURL.String()) 
    if err == nil { 
     body, _ := ioutil.ReadAll(sourceResponse.Body) 
     client.Post(destinationURL.String(), "text/html", strings.NewReader(string(body))) 
    } 
} 

但是这将整个响应读入内存 - 如何将响应流式传输到POST请求?这是我想要的:

func deliver(sourceURL *url.URL, destinationURL *url.URL) { 
    client := &http.Client{} 
    sourceResponse, err := http.Get(sourceURL.String()) 
    if err == nil { 
     client.Post(destinationURL.String(), "text/html", sourceResponse.Body) 
    } 
} 

我会假设这会工作,但它只发送一个空请求(没有正文)。为什么是这样? client.Post函数是不是实际尝试读取响应?

这里的随身操场一个例子:http://play.golang.org/p/_EO80aj6wr 发送的dataReader代替sourceResponse.Body作品完美,但在发送sourceResponse.Body直接不起作用。

实例链接:

http://localhost:3000/fetch?dest=http://requestb.in/177ji621&src=http://www.google.com 
http://requestb.in/177ji621?inspect 

回答

2

我做了一个小测试程序尝试了这一点

package main 

import (
    "fmt" 
    "io/ioutil" 
    "log" 
    "net/http" 
    "net/url" 
) 

var client = &http.Client{} 

func httpd() { 
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 
     log.Printf("%s Request from %s", r.Method, r.RemoteAddr) 
     if r.Method == "GET" { 
      fmt.Fprintf(w, "Here is a GET body") 
      return 
     } 
     body, err := ioutil.ReadAll(r.Body) 
     if err != nil { 
      log.Fatalf("body read failed: %v", err) 
     } 
     log.Printf("Body received from %s: %q", r.Method, body) 
    }) 
    log.Fatal(http.ListenAndServe(":8080", nil)) 
} 

func deliver(sourceURL *url.URL, destinationURL *url.URL) { 
    sourceResponse, err := http.Get(sourceURL.String()) 
    if err != nil { 
     log.Fatalf("post failed: %v", err) 
    } 
    postResponse, err := client.Post(destinationURL.String(), "text/html", sourceResponse.Body) 
    if err != nil { 
     log.Fatalf("post failed: %v", err) 
    } 
    postResponse.Body.Close() 
    sourceResponse.Body.Close() 
} 

func main() { 
    go httpd() 
    src, err := url.Parse("http://127.0.0.1:8080/") 
    if err != nil { 
     log.Fatalf("src parse failed: %v", err) 
    } 
    dst, err := url.Parse("http://127.0.0.1:8080/") 
    if err != nil { 
     log.Fatalf("dst parse failed: %v", err) 
    } 
    deliver(src, dst) 
} 

它能正常工作,生产这种输出

2014/10/04 08:40:26 GET Request from 127.0.0.1:48910 
2014/10/04 08:40:26 POST Request from 127.0.0.1:48911 
2014/10/04 08:40:26 Body received from POST: "Here is a GET body" 

所以这个问题你代码可能会由你没有检查的错误 - Post中最可能的错误所揭示。

另请注意,如果可以的话,您想重新使用http.Client,这样您就可以获得连接池。


更新后审查更新的问题。

我试过我的测试程序http://requestb.in/,它不显示正文。但我确实看到这个Transfer-Encoding: chunked,所以我怀疑requestb.in不支持分块传输编码。

如果您提供整个机构的请求然后去设置Content-Length标题,但if you provide a stream然后去使用chunked transfer encoding。即使分块传输编码是HTTP/1.1规范的非可选部分,也有相当多的服务器不支持它。

+0

不知道为什么它不适合我。尝试检查所有错误,但没有问题。我可以确认请求正在发送,但主体仍然是空的。 – 2014-10-04 09:16:08

+0

如果您需要更多帮助,请发布一个演示问题的实例。 – 2014-10-04 10:07:04

+0

我已经在问题中添加了一个Go操场示例 - 看起来像我可以清晰地重现。 – 2014-10-04 10:44:09