一尘不染

在不修改请求状态的情况下读取http.Request的正文?

go

我有一个实现http.Handler接口的类型,该接口在其ServeHTTP方法中检查传入的HTTP请求,采取某些措施,然后将请求转发到反向代理处理程序(httputil.NewSingleHostReverseProxy)。

只要我仅检查基本的请求属性(例如URL或标头),此方法就可以正常工作。

当我想检查传入的POST请求的主体(例如,通过调用req.ParseForm()然后使用req.Form属性)时,将请求传递到反向代理后,就会遇到错误:

http: proxy error: http: Request.ContentLength=687 with Body length 0

我认为发生这种情况是因为查看HTTP请求的正文会导致req.Body.Reader流被耗尽,这意味着代理处理程序无法再次读取它。

我一直在玩诸如io.Copy()和这类的东西bufio.Peek(),但是我什么都没有。

有没有一种方法可以窥视HTTP请求主体(并使用内置的解析req.ParseForm等),同时将原始请求对象保留为原始状态,以便可以将其传递给反向代理?


阅读 207

收藏
2020-07-02

共1个答案

一尘不染

尝试读入缓冲区,然后使用缓冲区支持两个新的读取器,一个供您使用,另一个供以后的使用者使用。例如,假设我们要修改以下代码:

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

2020-07-02