用Golang重写HTTP请求体

12

我在服务器端使用Golang编写http拦截器。我可以从r.Body读取http请求正文。现在,如果我想修改正文内容,我该如何在控制权转交给下一个拦截器之前修改请求正文?

func(w http.ResponseWriter, r *http.Request) {
    // Now I want to modify the request body, and 
    // handle(w, r)
}

你能详细说明一下哪些类型的拦截器会控制并由谁将控制权传递给这些拦截器吗?还有,“客户端”是什么意思?你读取请求正文的代码至少是“一个”客户端。 - Volker
我添加了一些示例代码。本质上,我想修改响应并将其传递给下一个处理器。在HTTP服务器发送响应之前,我在服务器端也遇到了同样的问题。 - user1663023
13
你可以将整个请求体读取出来,进行修改后再放回请求中。类似于(伪代码)b = ioutil.ReadAll(r.Body); b[42] = 99; r.Body = ioutil.NopCloser(bytes.NewBuffer(b))。非常简单。 - Volker
4
非常感谢 @Volker。ioutil.NopCloser 是我正在寻找的东西。你能否把它作为答案,这样我就可以给你积分了吗? - user1663023
4
如果其他人遇到同样的问题:如果您更改了请求正文(Body)的长度,您还需要将 r.ContentLength 更新为新值。例如,newBody := "新正文"; r.Body = ioutil.NopCloser(strings.NewReader(newBody)); r.ContentLength = int64(len(newBody)) - Izak Marais
1
@Volker 你应该在ReadAll之后关闭原始r.Body。 - dr.scre
1个回答

22

Body io.ReadCloser

似乎唯一的方法是用适合io.ReadCloser接口的对象替换Body。为此,您需要使用返回io.Reader对象的任何函数构造Body对象,并使用ioutil.NopCloserio.Reader对象转换为io.ReadCloser

bytes.NewBufferString

NewBufferString创建并初始化一个新的Buffer,使用字符串s作为其初始内容。它旨在准备缓冲区以读取现有字符串。

strings.NewReader (在下面的示例中使用)

NewReader返回从s读取的新Reader。它类似于bytes.NewBufferString但更高效且只读。

ioutil.NopCloser

NopCloser返回具有包装所提供的Reader r的无操作Close方法的ReadCloser。

new_body_content := "New content."
r.Body = ioutil.NopCloser(strings.NewReader(new_body_content))

相关属性

但需要明确的是,为了不混淆应用程序的其他部分,您需要更改与Body内容相关的Request属性。大多数情况下只需更改ContentLength属性即可:

r.ContentLength = int64(len(new_body_content))

在极少数情况下,如果您的新内容使用与原始Body不同的编码方式,则可能会出现TransferEncoding


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接