一文告知HTTP GET是否可以有请求体

HTTP GET是否可以有请求体

先说结论:

HTTP协议没有规定GET请求不能携带请求体,但是部分浏览器会不支持,因此不建议GET请求携带请求体。

  • HTTP 协议没有为 GET 请求的 body 赋予语义,也就是即不要求也不禁止 GET 请求带 body。
  • 大多数 HTTP 实现从技术上都支持 HTTP GET 请求带 body,少数实现会禁止(google-chrome 浏览器、node-fetch),少数实现会不建议(Fiddler)。

1 HTTP协议对GET请求包含BODY的规定

1.1 RC1945

RFC 1945 发布于 1996 年,描述了 HTTP/1.0 。

其中和 body 有关的第 7 节提到了一下内容:

Full-Request and Full-Response messages may transfer an entity within some requests and responses. An entity consists of Entity-Header fields and (usually) an Entity-Body.

译:Full-Request 和 Full-Response 消息可以在某些请求和响应中传输实体。实体包括实体首部字段,并且通常包括一个实体 body。

说明 HTTP/1.0 会通过请求或响应的 body 传输实体,并且没有限定哪些请求方法不能传输实体。也就是说 GET 也可以有 body。

另外其 8.1 节关于 GET 和 POST 方法有如下描述:

The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.

译:GET 方法表示查询由 Request-URI 标识的任何信息(形式为实体)。

The POST method is used to request that the destination server accept the entity enclosed in the request ...

译:POST 方法用于请求目标服务器接受包含在请求中的实体 ...

说明 GET 方法的语义是请求实体,POST 方法的语义是提交实体,两者有明确的分工。

RFC 1945 这两处的内容可以提炼出两条信息:

  1. 请求或响应需要传输实体时才会有 body。
  2. GET 请求用于请求实体,而不是传输实体。
    根据这两条信息可以推出,GET 请求没有传输实体的语义,自然也不需要 body。但 RFC 1945 也没有明确规定 GET 请求不能传输实体、不能有 body。所以按 HTML 1.0 规范,GET 请求是可以有 body 的,只不过没有为其定义语义。

1.2 RFC 2068

RFC 2068 发布于 1997 年,描述了 HTTP/1.1。

RFC 2068 是对 RFC 1945 的更新,在 4.3 节有以下描述:

A message-body MAY be included in a request only when the request method allows an entity-body.

译:只有当请求方法允许使用实体 body 时,请求中才可以包含消息 body。

第 9 节是关于各个 HTTP 请求方法的描述,但只有第 9.8 节提到:

A TRACE request MUST NOT include an entity.

译:TRACE 请求必须不能包含实体。

另外,对 PUT、POST 的描述都默认有实体。但是对 GET 描述并没有提到请求中是否能包含实体 body。

也就是说 TRACE 不允许包含 body,PUT、POST 请求包含 body,但是 GET 没有明确说明,这种没说明的情况到底是允许还是不允许呢?

1.3 RFC 2616

RFC 2616 发布于 1999 年,是对 RFC 2068 的更新,还是描述的 HTTP/1.1。

其 4.3 节增加了如下描述:

A message-body MUST NOT be included in a request if the specification of the request method does not allow sending an entity-body in requests. A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.

译:如果本规范规定了某个请求方法不允许发送实体,则绝不能在请求中包含消息 body。服务器应该读取和转发任何请求的消息体(body);如果某个请求方法没有定义实体语义,那么在处理请求时应该忽略消息体(body)。

但第 9 节对于各个方法的描述中还是没有说 GET 请求是否能有 body。

1.4 RFC 7231

2004 年发布的 RFC 7230~7235 是对 RFC 2626 的修订。其中 RFC 7231 是 HTTP 的"核心"语义规范,终于在 4.3.1 节明确提到了 GET 请求的 body:

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 请求上发送有效负载主体可能会导致某些现有实现拒绝该请求。

说明修订规范的人也知道有的 HTTP server 实现会拒绝带有 body 的 HTTP GET 请求。但是为什么规范迭代了这么多次都不规定每个请求方法是否能包含 body 呢?留下这么大的争议空间也是醉了。

2 现有实现对 GET 请求 body 的支持

请求库/工具 是否支持GET带body
XMLHttpRequest 不支持
Fetch 不支持
Requests(Python最流行的HTTP请求库) 支持
HTTPX(Python库) 支持
axios(基于Promise的HTTPClient库) 支持
superagent 支持
node-fetch(Node.js的一个HTTP请求库) 不支持
curl 支持
Postman 支持
Apifox 支持
Fiddler 支持,但是会用红色告警
nginx 支持
FastAPI 支持
  • Fildder发送GET请求红色警告⚠️图:

3 结论

🚀HTTP协议中没有明确规定GET请求是否能带body,市场上部分浏览器会不支持GET请求带body。

软件工程中有一条原则:不要依赖未定义的行为。HTTP 协议未定义 GET 请求的 body 语义,如果想用 GET 请求发送 body,得先为其定义语义,并确保上下游都能很好的支持。作为服务接口的提供方,不应该假设所有的调用方都能发出 GET 请求 body;作为调用方,不应该假设服务方能完美解析 GET 请求 body,但如果服务方提供了支持 GET 请求 body 的接口,可以放心使用,不用纠结。

软件工程中还有另一条原则,不记得原文了,翻译成中国的老话就是:严于律己,宽已待人。我们在写库、写框架、写工具时应该支持 GET 请求带 body;在封装接口时,尽量不要强制调用方用 GET body 提交数据,除非遇到用 GET body 才符合逻辑的特殊情况;在使用别人提供的库、框架、工具,或者调用协作方提供的接口时不应该强求对方支持 GET 请求 body。

参考文章:

https://zhuanlan.zhihu.com/p/456921996

相关推荐
我也要当昏君9 小时前
6.3 文件传输协议 (答案见原书 P277)
网络
Greedy Alg10 小时前
Socket编程学习记录
网络·websocket·学习
刘逸潇200510 小时前
FastAPI(二)——请求与响应
网络·python·fastapi
软件技术员11 小时前
使用ACME自动签发SSL 证书
服务器·网络协议·ssl
我也要当昏君11 小时前
6.4 电子邮件 (答案见原书 P284)
网络协议
Mongnewer11 小时前
通过虚拟串口和网络UDP进行数据收发的Delphi7, Lazarus, VB6和VisualFreeBasic实践
网络
我也要当昏君12 小时前
6.5 万维网(答案见原书P294)
网络
嶔某12 小时前
网络:传输层协议UDP和TCP
网络·tcp/ip·udp
文火冰糖的硅基工坊12 小时前
[嵌入式系统-154]:各种工业现场总线比较
网络·自动驾驶·硬件架构
以己之12 小时前
详解TCP(详细版)
java·网络·tcp/ip