HTTP GET с телом запроса - PullRequest
       217

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

1726 голосов
/ 11 июня 2009

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

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

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

Мои вопросы:

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

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

Ответы [ 18 ]

1441 голосов
/ 12 июня 2009

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

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

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

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

.... Roy

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

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

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

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

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

Обновление RFC2616, называемый «HTTP / 1.1 spec», теперь устарел. В 2014 году он был заменен RFC 7230-7237. Цитата «тело сообщения ДОЛЖНО игнорироваться при обработке запроса» была удалена. Теперь это просто «Запрос на создание кадра не зависит от семантики метода, даже если метод не определяет никакого использования для тела сообщения». Вторая цитата: «Метод GET означает получение любой информации ... идентифицированной по Request-URI» был удален - из комментария

259 голосов
/ 11 июня 2009

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

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

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

130 голосов
/ 11 июня 2009

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

66 голосов
/ 27 марта 2013

Ни restclient , ни Консоль REST не поддерживают это, но curl поддерживает.

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

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

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

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

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

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

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

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

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

44 голосов
/ 03 декабря 2013

Elasticsearch принимает GET-запросы с телом. Даже кажется, что это предпочтительный способ: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

Некоторые клиентские библиотеки (например, драйвер Ruby) могут регистрировать команду cry в stdout в режиме разработки, и он широко использует этот синтаксис.

29 голосов
/ 11 июня 2009

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

Вы можете просто создать свой конкретный медиатип поиска или, если вы хотите быть более RESTful, использовать что-то вроде OpenSearch и отправить POST запрос на URI, указанный сервером, скажем / search Затем сервер может сгенерировать результат поиска или создать окончательный URI и перенаправить с помощью 303.

Преимущество заключается в том, что он следует традиционному методу PRG, помогает кешировать посредников в кеше результатов и т. Д.

Тем не менее, URI в любом случае кодируются для всего, что не является ASCII, как и application / x-www-form-urlencoded и multipart / form-data. Я бы рекомендовал использовать это, а не создавать еще один пользовательский формат json, если вы намерены поддерживать сценарии ReSTful.

21 голосов
/ 30 июня 2013

Какой сервер его проигнорирует? - Фиджиарон 30 августа 12 года в 21: 27

Например, Google делает хуже, чем игнорирует его, он будет считать ошибку !

Попробуйте сами с простой сетевой кошкой:

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

1234

(за содержимым 1234 следует CR-LF, то есть всего 6 байтов)

и вы получите:

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.

Вы также получаете 400 плохих запросов от Bing, Apple и т. Д., Которые обслуживаются AkamaiGhost.

Так что я бы не советовал использовать запросы GET с сущностью тела.

21 голосов
/ 31 августа 2012

Вы можете отправить GET с телом или отправить POST и отказаться от RESTish религиозности (это не так уж и плохо, 5 лет назад в этой вере был только один член - его комментарии связаны выше).

Также не являются хорошими решениями, но отправка тела GET может предотвратить проблемы для некоторых клиентов - и некоторых серверов.

Выполнение POST может иметь препятствия с некоторыми средами RESTish.

Джулиан Решке предложил выше использовать нестандартный HTTP-заголовок, такой как «ПОИСК», который может быть элегантным решением, за исключением того, что он еще менее вероятно будет поддерживаться.

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

Клиенты, которые не могут отправить GET с телом (о котором я знаю):

  • XmlHTTPRequest Fiddler

Клиенты, которые могут отправить GET с телом:

  • большинство браузеров

Серверы и библиотеки, которые могут получить тело из GET:

  • Apache
  • PHP

Серверы (и прокси), которые снимают тело с GET:

17 голосов
/ 07 марта 2014

С RFC 2616, раздел 4.3 , «Тело сообщения»:

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

То есть серверы всегда должны читать любое предоставленное тело запроса из сети (установите флажок Content-Length или read chunked body и т. Д.). Кроме того, прокси-серверы должны пересылать любое такое тело запроса, которое они получают. Затем, если RFC определяет семантику для тела для данного метода, сервер может фактически использовать тело запроса при генерации ответа. Однако если RFC не определяет семантику для тела, то сервер должен игнорировать ее.

Это соответствует приведенной выше цитате из Филдинга.

Раздел 9.3 , «GET», описывает семантику метода GET и не упоминает тела запросов. Поэтому сервер должен игнорировать любое тело запроса, которое он получает по запросу GET.

14 голосов
/ 28 июля 2016

Я поставил этот вопрос в IETF HTTP WG. Комментарий Роя Филдинга (автора документа http / 1.1 в 1998 году) заключался в том, что

"... реализация будет нарушена для выполнения чего-либо, кроме анализа и удаления этого тела, если оно получено" *

RFC 7213 (HTTPbis) заявляет:

"Полезная нагрузка в сообщении запроса GET не имеет определенной семантики;"

Теперь ясно, что предполагалось, что семантическое значение в телах запросов GET запрещено, что означает, что тело запроса не может использоваться для воздействия на результат.

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

Итак, в общем, не делайте этого.

...