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.
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 请求的载荷么有语义,某些实现里可能会拒绝 GET 请求携带请求体。意思就是:你们咋实现都行,拒不拒绝你们说了算。
那么总结起来就是,这是一个早年某些浏览器的“Feature”,结果成了主流共识了;但 Server 们不吃这一套,也支持 GET 带请求体。
不是,它们都和 POST 一样,是可以携带请求体的(即 body)。
P.S. 其他仨跟 GET 的“区别”还有段历史问题,先🐎上,一会儿再更新。
【更新来了】
大家普遍有这样一个认知:GET 请求不能包含请求体、POST/PUT/DELETE 请求才可以。但这个说法其实是有问题的。
其实最早的 HTTP/1.0 规范 —— RFC-1945 里只规定了:
并没有约束 GET 请求不可以携带请求体。
等到 HTTP/1.1 规范 —— RFC-2612 又有了两条新说说法:
这两段话里提到了两点,一个从客户端角度出发,规定语义上不该包含请求体的请求,禁止发送请求体;一个从服务端角度触发,规定语义上不该包含请求体的请求,服务端在处理时应该忽略请求体。
但要注意的是,第一点在举例上只提到了 TRACE 这个谓词不允许发送请求体;而关于第二点,却并没有举例到底有哪些谓词是“从语义上说不该包含请求体”的,况且即便举例了,这里的措辞也是一个比较温和的“SHOULD”。
但 HTTP/1.1 于 1997 年 1 月发布后,很快就迎来了互联网浪潮(想想 2000 年的互联网泡沫,年纪大一些的应该有不少人听过吧),在这个其间浏览器蓬勃发展,很多浏览器在实现上都把 GET 视为上面提到的“从语义上说不该包含请求体”的谓词,也慢慢为大众所接受。
而作为服务端们,其实并没有遵循这一点,绝大部分主流 WebServer 和后端编程语言里,都是支持 GET 请求携带请求体的。这点上就跟作为客户端的浏览器分道扬镳。
鉴于这种分裂的局面,时隔 17 年后 RFC-7230 又改变了措辞:
这又变成了请求谓词和请求体解耦了,二者没有关系了。
但此时已经到了 2014 年,浏览器早就更新换代不知道多少次了,这个祖传的“GET 不能带请求体”早已经变成了一个 Feature,再想改已经积重难返了。所以浏览器和 Server 们在这点上实现上还是不一样。
可能有感于这种分裂局面不会迎来统一了,紧接着 RFC-7231 又开始甩锅了:
说 GET 请求的载荷么有语义,某些实现里可能会拒绝 GET 请求携带请求体。意思就是:你们咋实现都行,拒不拒绝你们说了算。
那么总结起来就是,这是一个早年某些浏览器的“Feature”,结果成了主流共识了;但 Server 们不吃这一套,也支持 GET 带请求体。
事实上如果你的客户端程序不是用 JS 跑在浏览器里,而是其他编程语言来发送 HTTP 请求(比如用 Java / C# / PHP 等等),GET 请求也是可以带请求体的。
P.S. 浏览器还有个实现和 HTTP 规范不统一的地方,那就是 HTTP 缓存,这里就不展开讲了。