我有一个实现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等解析),同时将原始请求对象保持在其原始状态,以便将其传递给反向代理?

推荐答案

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

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中.

Go相关问答推荐

Golang regexpp:获取带有右括号的单词

gorm如何声明未自动更新的unix时间戳米尔斯字段

如何在定制普罗米修斯出口商中测试动态计量注册?

Makefile:现有文件上没有这样的文件或目录,不加载环境变量

Kafka架构注册表-Broker:Broker无法验证记录

如何在gofiber/websocket/v2中设置状态代码和原因

死锁 - 所有 goroutine 都处于睡眠状态(即使使用等待组)

该文件位于模块.内,该模块不包含在您的工作区中

Go Template 动态获取变量

在 Golang 中查看目录是否可写的跨平台方式?

我突然无法再将我的 GoLang 应用程序部署到 Google AppEngine

如果 transaction.Commit 对带有 postgres 连接的 SQL 失败,您是否需要调用 transaction.RollBack

如何在golang中按字符a对字符串数组进行排序

Golang - 将 [8] 布尔转换为字节

Go 并发、goroutine 同步和关闭通道

Golang grpc go.mod 问题

是否可以使用按位运算在随机 unicode 字符串中找到重复字符?

Golang - 使用正则表达式提取链接

HTTP 重定向不呈现新页面

带有 grpc 的 protobuf 用于拆分包中的 Go