我有一个实现http.Handler
接口的类型,在其ServeHTTP
方法中,检查传入的HTTP请求,执行某些操作,然后将请求转发到反向代理处理程序({ {1}})。
这样可以正常工作,只要我只检查基本的请求属性,例如URL或标题。
当我想检查传入的POST请求的正文时,例如通过调用httputil.NewSingleHostReverseProxy
然后使用req.ParseForm()
属性,一旦请求传递到反向代理,我就会遇到错误:
req.Form
我想这是因为查看HTTP请求的主体会导致http: proxy error: http: Request.ContentLength=687 with Body length 0
流被耗尽,这意味着代理处理程序无法再次读取它。
我一直在玩req.Body.Reader
和io.Copy()
之类的东西,但我并没有真正到达任何地方。
有没有办法窥视HTTP请求体(并使用内置的bufio.Peek()
解析等),同时保留原始请求对象的原始状态,以便可以将其传递给反向代理?
答案 0 :(得分:58)
尝试读入缓冲区,然后使用缓冲区备份两个新读者,一个供您使用,另一个供后续消费者使用。例如,假设我们要修改以下代码:
doStuff(r.Body) // r is an http.Request
我们可以做到:
buf, _ := ioutil.ReadAll(r.Body)
rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf))
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
doStuff(rdr1)
r.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface
// Now the program can continue oblivious to the fact that
// r.Body was ever touched.
请注意,*bytes.Buffer
没有Close() error
方法,因此它不会实现io.ReadCloser
接口。因此,我们必须在*bytes.Buffer
的调用中包含ioutil.NopCloser
值。
答案 1 :(得分:-1)
我最近采用了不同的方法。有一种GetBody
方法可用,您可以通过该方法获取请求正文的新副本,而不是执行:
doStuff(r.Body)
你可以这样做:
body, _ := r.GetBody()
doStuff(body)
// r.Body is unmodified
这允许您检查请求正文,同时仍然可以在以后进行进一步处理