Golang中HTTP Client RoundTripper为Payload添加多余外层对象求助
问题解决:Go HTTP Client自定义RoundTripper中Payload看似被多包裹一层的问题
问题现象
使用Go的HTTP Client时,传入http.NewRequest的Payload是{"message":"Hello, world!"},但在自定义RoundTripper里打印Payload时,显示为{{"message":"Hello, world!"}},误以为Payload被多包裹了一层。
原因分析
问题出在错误的打印方式:代码中直接用%s格式化req.Body,而req.Body是io.ReadCloser类型(此处实际为*bytes.Buffer),*bytes.Buffer的String()方法返回格式为{buf},其中buf是实际的JSON内容,所以打印出来会呈现{{...}}的样子。实际发送的请求Payload并没有被多包裹,只是打印显示错误。
正确解决方案
要正确获取并打印请求Body的内容,需要先读取req.Body的字节数据,读取完成后要重新设置Body(因为读取后Body的读取指针会移到末尾,后续的RoundTripper无法再读取)。
修改后的代码
package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) type Object struct { Message string `json:"message"` } type myRoundTripper struct { roundTripper http.RoundTripper } func (rt *myRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // 读取Body内容 bodyBytes, err := io.ReadAll(req.Body) if err != nil { return nil, err } // 重新设置Body,确保后续RoundTripper能正常读取 req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) fmt.Printf("2. Payload in RoundTrip: %s\n", string(bodyBytes)) return rt.roundTripper.RoundTrip(req) } func main() { object := Object{ Message: "Hello, world!", } payload, err := json.Marshal(object) if err != nil { panic(err) } fmt.Printf("1. Original Payload: %s\n", string(payload)) client := &http.Client{ Transport: &myRoundTripper{ roundTripper: http.DefaultTransport, }, } req, err := http.NewRequest(http.MethodPost, "http://localhost:8080/", bytes.NewBuffer(payload)) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") res, err := client.Do(req) if err != nil { panic(err) } fmt.Printf("Response: %v\n", res) }
验证输出
运行修改后的代码,输出会显示正确的Payload:
$ go run main.go 1. Original Payload: {"message":"Hello, world!"} 2. Payload in RoundTrip: {"message":"Hello, world!"} Response: &{200 OK 200 HTTP/1.1 1 1 map[Content-Length:[240] Content-Type:[text/plain; charset=utf-8] Date:[Sun, 27 Oct 2024 16:24:31 GMT] Status:[200 OK]] 0xc000034140 240 [] false false map[] 0xc0000de360 <nil>}
注意事项
- 读取
req.Body后必须重新设置,否则后续的HTTP传输会因为Body已被读取完毕而无法发送正确的请求内容。 - 使用
io.NopCloser包装bytes.Buffer,因为http.Request.Body要求是io.ReadCloser类型,bytes.Buffer只有io.Reader,NopCloser会给它添加一个空的Close()方法。
内容的提问来源于stack exchange,提问作者Yasuhiro Yamazaki
相关产品推荐
相关产品推荐

