Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在不修改请求状态的情况下读取http.Request的正文?_Http_Io_Go - Fatal编程技术网

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

在不修改请求状态的情况下读取http.Request的正文?,http,io,go,Http,Io,Go,我有一个实现http.Handler接口的类型,在它的ServeHTTP方法中,检查传入的http请求,采取一些操作,然后将请求转发到反向代理处理程序(httputil.newsinglehostreverseeproxy) 只要我只检查基本的请求属性,比如URL或头,这就行了 当我想检查传入POST请求的主体时,例如,通过调用req.ParseForm()然后使用req.Form属性,当请求传递到反向代理时,我会遇到一个错误: http:proxy错误:http:Request.Content

我有一个实现
http.Handler
接口的类型,在它的
ServeHTTP
方法中,检查传入的http请求,采取一些操作,然后将请求转发到反向代理处理程序(
httputil.newsinglehostreverseeproxy

只要我只检查基本的请求属性,比如URL或头,这就行了

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

http:proxy错误:http:Request.ContentLength=687,正文长度为0

我认为这是因为查看HTTP请求的主体会导致
req.body.Reader
流被耗尽,这意味着代理处理程序无法再次读取它

我一直在玩
io.Copy()
bufio.Peek()
之类的游戏,但我并没有真正取得任何进展


有没有一种方法可以窥视HTTP请求主体(并使用
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()错误
方法,因此它没有实现
io.ReadCloser
接口。因此,我们必须在调用
ioutil.nocloser

时包装
*bytes.Buffer
值。最近我使用了不同的方法来处理这个问题。有一个可用的
GetBody
方法,您可以通过该方法获取请求正文的新副本,因此不必执行以下操作:

doStuff(r.Body)
你可以改为:

body, _ := r.GetBody()
doStuff(body)
// r.Body is unmodified

这允许您在检查请求正文的同时仍保留它,以便稍后进行进一步处理

您是否尝试过用可查找的读取器(如
字节读取器)替换
正文
?您可以将
Body
设置为实现
ReadCloser
的每个值。未测试(但值得一试):根据需要制作请求的深度副本,即除了Body和。*表单之外的所有内容。然后使用io.teereder克隆Request.Body,将其包装在NoCloser中,并填充到请求的deepcopy中。将深度副本传递给反向代理。是的,np!很好地捕捉到了密切的签名。我想阅读文档毕竟很重要;)您可以使用
io.nocloser
功能从缓冲区获取
io.ReadCloser
,例如
io.nocloser(buf)
。请看,TeeReader可能会很有用。这很有效,但仅适用于可以保存在内存或磁盘中的绑定实体。
drainBody
in提供了类似的解决方案,但考虑了
http。没有人将其考虑在内。
GetBody()
仅用于客户端请求。对于服务器请求,它是未使用的。