Вопрос: HTTP GET с телом запроса


Я разрабатываю новый веб-сервис RESTful для вашего приложения.

При выполнении GET на определенных объектах клиенты могут запрашивать содержимое объекта. Если они хотят добавить некоторые параметры (например, отсортировать список), они могут добавить эти параметры в строку запроса.

В качестве альтернативы я хочу, чтобы люди могли указать эти параметры в теле запроса. HTTP / 1.1 похоже, явно не запрещает это. Это позволит им указать больше информации, может упростить определение сложных xml-запросов.

Мои вопросы:

  • Это хорошая идея?
  • Будут ли у клиентов HTTP проблемы с использованием органов запроса в запросе GET?

http://tools.ietf.org/html/rfc2616


1383


источник


Ответы:


Комментарий Роя Филдинга о включении тела с запросом GET ,

Да. Другими словами, любое сообщение HTTP-запроса может содержать   тело сообщения и, таким образом, должно анализировать сообщения с учетом этого.   Однако семантика сервера для GET ограничена таким образом, что тело,   если таковые имеются, не имеет семантического значения для запроса. Требования   при разборе отдельно от требований по семантике метода.

Итак, да, вы можете отправить тело с GET, и нет, он никогда не будет полезен   для этого.

Это часть многоуровневой конструкции HTTP / 1.1, которая станет   снова очистите, когда спецификация разделена (выполняется работа).

....Рой

Да, вы можете отправить тело запроса с GET, но оно не должно иметь никакого значения. Если вы придаете этому значение, разобрав его на сервере и изменение вашего ответа на основе его содержимого , то вы игнорируете эту рекомендацию в спецификация HTTP / 1.1, раздел 4.3 :

[...] если метод запроса      не включает определенную семантику для объекта-тела, тогда      тело сообщения ДОЛЖЕН при обращении с запросом игнорироваться.

И описание метода GET в спецификация HTTP / 1.1, раздел 9.3 :

Метод GET означает получение любой информации ([...]), идентифицируемой Request-URI.

в котором указано, что тело запроса не является частью идентификации ресурса в запросе GET, а только URI запроса.


1182



Пока ты Можно сделайте это, поскольку это явно не запрещено спецификацией HTTP, я бы предложил избегать этого просто потому, что люди не ожидают, что что-то будет работать таким образом. В цепочке запросов HTTP есть много фаз, и, хотя они «в основном» соответствуют спецификации HTTP, единственное, что вы уверены, это то, что они будут вести себя традиционно, используя веб-браузеры. (Я думаю о вещах, таких как прозрачные прокси, ускорители, инструментальные средства A / V и т. Д.)

Это дух, стоящий за Принцип надежности грубо говоря, «быть либеральным в том, что вы принимаете, и консервативным в том, что вы отправляете», вы не хотите четко указывать границы спецификации.

Однако, если у вас есть веская причина, пойдите для этого.


231



Вы, вероятно, столкнетесь с проблемами, если попытаетесь воспользоваться кешированием. Прокси не собираются смотреть в тело GET, чтобы увидеть, влияют ли параметры на ответ.


113



ни restclient ни Консоль REST поддерживайте это, но скручивание.

Спецификация HTTP говорится в разделе 4.3

Тело сообщения НЕ ДОЛЖНО быть включено в запрос, если спецификация метода запроса (раздел 5.1.1) не позволяет отправлять тело объекта в запросы.

Раздел 5.1.1 перенаправляет нас в раздел 9.x для различных методов. Ни один из них явно не запрещает включение тела сообщения. Однако...

Раздел 5.2. говорит

Точный ресурс, идентифицированный с помощью интернет-запроса, определяется путем изучения поля Request-URI и заголовка Host.

а также Раздел 9.3 говорит

Метод GET означает получение любой информации (в форме объекта), идентифицируемой Request-URI.

Что вместе предполагает, что при обработке запроса GET сервер не обязательный для изучения чего-либо другого, что поля заголовка Request-URI и Host.

Таким образом, спецификация HTTP не мешает вам отправлять тело сообщения с GET, но есть достаточная двусмысленность, что меня не удивит, если он не будет поддерживаться всеми серверами.


60



Elasticsearch accepts GET requests with a body. It even seems that this is the preferred way : http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

Some client libraries (like the Ruby driver) can log the cry command to stdout in development mode and it is using this syntax extensively.


35



What you're trying to achieve has been done for a long time with a much more common method, and one that doesn't rely on using a payload with GET.

You can simply build your specific search mediatype, or if you want to be more RESTful, use something like OpenSearch, and POST the request to the URI the server instructed, say /search. The server can then generate the search result or build the final URI and redirect using a 303.

This has the advantage of following the traditional PRG method, helps cache intermediaries cache the results, etc.

That said, URIs are encoded anyway for anything that is not ASCII, and so are application/x-www-form-urlencoded and multipart/form-data. I'd recommend using this rather than creating yet another custom json format if your intention is to support ReSTful scenarios.


25



Which server will ignore it? – fijiaaron Aug 30 '12 at 21:27

Google for instance is doing worse than ignoring it, it will consider it an error!

Try it yourself with a simple netcat:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(the 1234 content is followed by CR-LF, so that is a total of 6 bytes)

and you will get:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

You do also get 400 Bad Request from Bing, Apple, etc... which are served by AkamaiGhost.

So I wouldn't advise using GET requests with a body entity.


23



You can either send a GET with a body or send a POST and give up RESTish religiosity (it's not so bad, 5 years ago there was only one member of that faith -- his comments linked above).

Neither are great decisions, but sending a GET body may prevent problems for some clients -- and some servers.

Doing a POST might have obstacles with some RESTish frameworks.

Julian Reschke suggested above using a non-standard HTTP header like "SEARCH" which could be an elegant solution, except that it's even less likely to be supported.

It might be most productive to list clients that can and cannot do each of the above.

Clients that cannot send a GET with body (that I know of):

  • XmlHTTPRequest Fiddler

Clients that can send a GET with body:

  • most browsers

Servers & libraries that can retrieve a body from GET:

  • Apache
  • PHP

Servers (and proxies) that strip a body from GET:

  • ?

21



From RFC 2616, section 4.3, "Message Body":

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.

That is, servers should always read any provided request body from the network (check Content-Length or read a chunked body, etc). Also, proxies should forward any such request body they receive. Then, if the RFC defines semantics for the body for the given method, the server can actually use the request body in generating a response. However, if the RFC does not define semantics for the body, then the server should ignore it.

This is in line with the quote from Fielding above.

Section 9.3, "GET", describes the semantics of the GET method, and doesn't mention request bodies. Therefore, a server should ignore any request body it receives on a GET request.


16



I put this question to the IETF HTTP WG. The comment from Roy Fielding (author of http/1.1 document in 1998) was that

"... an implementation would be broken to do anything other than to parse and discard that body if received"

RFC 7213 (HTTPbis) states

"A payload within a GET request message has no defined semantics;"

It seems clear now that the intention was that semantic meaning on GET request bodies is prohibited, which means that the request body can't be used to affect the result.

There are proxies out there that will definitely break your request in various ways if you include a body on GET.

So in summary, don't do it.


11



If you really want to send cachable JSON/XML body to web application the only reasonable place to put your data is query string encoded with RFC4648: Base 64 Encoding with URL and Filename Safe Alphabet. Of course you could just urlencode JSON and put is in URL param's value, but Base64 gives smaller result. Keep in mind that there are URL size restrictions, see What is the maximum length of a URL in different browsers? .

You may think that Base64's padding = character may be bad for URL's param value, however it seems not - see this discussion: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . However you shouldn't put encoded data without param name because encoded string with padding will be interpreted as param key with empty value. I would use something like ?_b64=<encodeddata>.


7