我有一个实现http.Handler接口的类型,该接口在其ServeHTTP方法中检查传入的HTTP请求,采取某些措施,然后将请求转发到反向代理处理程序(httputil.NewSingleHostReverseProxy)。
http.Handler
ServeHTTP
httputil.NewSingleHostReverseProxy
只要我仅检查基本的请求属性(例如URL或标头),此方法就可以正常工作。
当我想检查传入的POST请求的主体(例如,通过调用req.ParseForm()然后使用req.Form属性)时,将请求传递到反向代理后,就会遇到错误:
req.ParseForm()
req.Form
http: proxy error: http: Request.ContentLength=687 with Body length 0
我认为发生这种情况是因为查看HTTP请求的正文会导致req.Body.Reader流被耗尽,这意味着代理处理程序无法再次读取它。
req.Body.Reader
我一直在玩诸如io.Copy()和这类的东西bufio.Peek(),但是我什么都没有。
io.Copy()
bufio.Peek()
有没有一种方法可以窥视HTTP请求主体(并使用内置的解析req.ParseForm等),同时将原始请求对象保留为原始状态,以便可以将其传递给反向代理?
req.ParseForm
尝试读入缓冲区,然后使用缓冲区支持两个新的读取器,一个供您使用,另一个供以后的使用者使用。例如,假设我们要修改以下代码:
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。
*bytes.Buffer
Close() error
io.ReadCloser
ioutil.NopCloser