我想要一个Request,并使用ParseForm检查一些数据,然后将相同的数据发送给proxy,如果我这样做,我们有问题
这样的错误日志
2020/05/26 15:34:47 http:代理错误:net / http:HTTP / 1.x传输连接断开:http:ContentLength = 32,主体长度为0
所以我终于弄清楚了,ParseForm()很好地关闭了Request .body
这是工作代理代码
url, _ := url.Parse(config.GetGameHost())
proxy := httputil.NewSingleHostReverseProxy(url)
r.URL.Host = url.Host
r.URL.Scheme = url.Scheme
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
r.Host = url.Host
proxy.ServeHTTP(w, r)
所以,我想我也需要克隆深度克隆请求,也要获取我的数据,也要发送原始请求,也要代理 我也编辑我的代码
nr := r.Clone(r.Context())
nr.ParseForm()
url, _ := url.Parse(config.GetGameHost())
proxy := httputil.NewSingleHostReverseProxy(url)
r.URL.Host = url.Host
r.URL.Scheme = url.Scheme
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
r.Host = url.Host
proxy.ServeHTTP(w, r)
并再次显示错误日志
2020/05/26 15:49:29 http:代理错误:net / http:HTTP / 1.x传输连接断开:http:ContentLength = 32,主体长度为0
Clone()不是深度克隆,还是我做错了?
------------这项工作------------
body, err := ioutil.ReadAll(r.Body)
if err != nil {
// ...
}
url, _ := url.Parse(config.GetGameHost())
r2 := r.Clone(r.Context())
r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))
r.ParseForm()
proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ServeHTTP(w, r2)
答案 0 :(得分:5)
http.Request.Body只能读取一次,需要复制一个新的正文。
body,err := ioutil.ReadAll(r)
if err != nil {
// ...
}
r2 := r.Clone(r.Context())
// clone body
r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))
// parse r1, proxy r2
r.ParseForm()
proxy.ServerHTTP(w, r2)
body对象默认为net.Conn多层封装。每次使用io.Reader接口读取4kb时,都可以节省内存使用量,通常在从网络读取时使用。
因此,只能从网络读取一次正文。如果要重复读取主体对象,则应全部读取,保存并使用。