在设计RESTful service时,可不可以在一个GET
请求中携带body?
答案是:最好不要这些做。
有一些RESTful service允许GET
请求携带request body,比如Elasticsearch的search接口。
但这不是一种好的实现。
HTTP的规范在定义GET
的语义时,规定server端应该只根据请求的URI来返回response。
[…] if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request. […] The GET method means retrieve whatever information ([…]) is identified by the Request-URI. […] 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.
一个特定的http server,比如Elasticsearch,可以支持带body的GET
。
但是也有很多http server会遵守规范,忽略GET
的body,比如代理、cache server等。
假如在Elasticsearch前放置一个http cache server,比如Varnish,那么Varnish在丢弃GET
的body后会返回一个错误的响应。
另外,一些http的客户端也可能不支持发送带body的GET
请求,比如一些Javascprit的http client。
(虽然用X-HTTP-Method-Override
header可以让http client以POST
的方式发送GET
请求来绕过这个限制,
但是如果请求流过某些代理,这些自定义的header可能会被丢弃。)
所以如果要在GET
请求里携带数据,最好放在query string里,或者自定义的header(比如X-CSRF-TOKEN
)、cookie里。
实际上,Elasticsearch也意识到这个问题,所以它支持通过query string来进行搜索。
(把整个body url encode之后放在source
参数里,然后在source_content_type
参数里指定source
的内容格式是application/json
。)
Elasticsearch还保留着对带body的GET
的支持,其中一个原因是大部分http client对URL的长度有限制。
如果你不像Elasticsearch这样需要在GET
请求中发送大量数据,最好还是使用query string来发送数据。