Go HTTP GET 请求可以发送 body 吗

前段时间遇到一个朋友,他跟我说他们在开发一个 Go 项目时 , 遇到了一个争议点,说来也好理解 。WEB UI 端选择 GET、POST 类型时,程序是否要区分所传递的值(例如:Body),还是不管是什么类型都传 。

Go HTTP GET 请求可以发送 body 吗

文章插图
一派认为无所谓,反正都能传 。又没限制 。
一派认为规范如此,不应该传 。应该针对 HTTP POST 类型 , 使用 POST 请求的 body 来传递参数 。在 GET 请求里使用 URI 来进行参数传递 。
看着似乎都有各自的道理,僵持不下 。
RFC7231 怎么说要看互联网协议的相关标准,必然是 RFC 了 。首先看看 RFC7231[1] 中的 4.3.1 小节是怎么说的 。
如下摘抄:
A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
大概意思:在 GET 类型的请求里使用 body 是一个没有定义的语义 。如果在 GET 请求的 body 里传递参数可能会被某些实现方拒绝该请求 。
也就是这个混着传的行为并不符合 RFC 规范 , 至少官方是不推荐不鼓励这样的使用方式 。但并没有禁止这个行为 。
记住这个结论 。接下来我们进行测试 。
程序支持程度我们起一个 HTTP Sever 用于测试和验证,看看在具体的编程语言的实现中是否可以支持 。
如下 Go 代码:
func hello(w http.ResponseWriter, req *http.Request) { b, _ := io.ReadAll(req.Body) w.Write(b)}func mAIn() { http.HandleFunc("/hello_world", hello) http.ListenAndServe(":7001", nil)}在命令行执行 CURL 进行测试:
$ curl -X GET localhost:7001/hello_world -d '煎鱼'煎鱼看来在 Go 里面是可以的 。
那既然 RFC 没有禁止,Go 的测试也正常 。看来就是只是口头上的 “不鼓励” 和 “不推荐” 吗?
那别的场景也都支持吗?
实际上也不是,例如:XMLHttpRequest 规范[2] 中有明确提到:
Go HTTP GET 请求可以发送 body 吗

文章插图
如果请求方法为 GET 或 HEAD , body 参数会被忽略 。
总结在 GET 类型里传 body 参数,从 RFC7231 标准来定义 。官方是不推荐、不鼓励这么去使用的 。
但是呢,这是一个没有明确禁止的事 。
而从各个 HTTP 实现的客户端来看,一开始还是有不少不支持的 。但掰扯了好多年后,大多数都支持了 。(毕竟用户的诉求也是很重要的)
甚至印象最深的,ES 直接就在 GET 请求里传了 body:
Go HTTP GET 请求可以发送 body 吗

文章插图
对应的 CURL:
curl -X GET "localhost:9200/my-index-000001/_search?from=40&size=20&pretty" -H 'Content-Type: Application/json' -d'{"query": {"term": {"user.id": "kimchy"}}}'但也有不支持的,例如在 Chrome 浏览器下测试 XMLHttpRequest、Fetch 对此都会忽略或出现报错 。
Go HTTP GET 请求可以发送 body 吗

文章插图
Fetch GET body
结论上来讲,GET 请求能不能传 body , 这是一个 RFC 规范不鼓励 。但是实现方大部分都支持的一个情况 。
企业和团队内部的话,建议达成研发规范的共识即可 。不过我个人而言,都会区分开 。
参考资料[1]RFC7231: https://datatracker.ietf.org/doc/pdf/rfc7231.pdf
[2]XMLHttpRequest 规范: https://xhr.spec.whatwg.org

【Go HTTP GET 请求可以发送 body 吗】


    推荐阅读