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

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

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

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

Мои вопросы:

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

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

10.06.2009 20:47:24
Преимущество заключается в том, что он позволяет легко отправлять тела запросов XML или JSON, он не имеет ограничений по длине и его проще кодировать (UTF-8).
Evert 10.06.2009 21:51:42
Если то, что вы ищете, является безопасным и идемпотентным методом, который позволяет запрашивать тела, вы можете посмотреть на SEARCH, PROPFIND и REPORT. Конечно, отсутствие GET и наличие тела запроса более или менее разрушает кеширование.
Julian Reschke 6.12.2011 09:33:16
@fijiaaron: Прошло 3 года, и с тех пор я приобрел большой опыт написания веб-сервисов. Это в основном все, что я делал за последние несколько лет. Я могу с уверенностью сказать, что это действительно очень плохая идея - добавить тело к GET-запросу. Лучшие два ответа стоят как скала.
Evert 31.08.2012 00:34:12
@Ellesedil: Проще говоря: любые преимущества использования GET по сравнению с POST существуют благодаря тому, как устроен HTTP. Эти преимущества больше не существуют, когда вы нарушаете стандарт таким образом. Поэтому остается только одна причина использовать GET + тело запроса вместо POST: эстетика. Не жертвуйте надежным дизайном ради эстетики.
Evert 1.05.2014 16:24:19
Чтобы подчеркнуть то, что сказал Эверт: «у него нет ограничения по длине». Если ваш GET с параметрами запроса нарушает ограничение длины (из 2048), то есть другой выбор, кроме как поместить информацию строки запроса в объект json, например, в тело запроса.
Kieran Ryan 17.05.2015 15:22:08
20 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

....Рой

Да, вы можете отправить тело запроса с помощью 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» был удален - из комментария

1697
11.01.2019 08:31:48
Кеширование / проксирование - две вещи, которые вы, скорее всего, сломаете, да. «Семантика» - это просто еще один способ сказать, «как люди, которые делают другие компоненты, будут ожидать, что другие компоненты будут работать». Если вы нарушаете семантику, вы с большей вероятностью увидите, что вещи ломаются в тех местах, где люди пишут вещи, которые ожидали, что вы соблюдаете эту семантику.
Stuart P. Bentley 18.08.2013 01:33:17
Elasticsearch - довольно важный продукт, использующий тела HTTP-запросов в GET. Согласно их руководству, должен ли HTTP-запрос поддерживать наличие тела или нет, не определено. Лично мне неудобно заполнять тело запроса GET, но у них, похоже, другое мнение, и они должны знать, что делают. astic.co/guide/en/elasticsearch/guide/current/…
GordonM 9.10.2015 16:22:41
@iwein, указывающий значения тел запроса GET, на самом деле не является нарушением спецификации. HTTP / 1.1 указывает, что серверам СЛЕДУЕТ игнорировать тело, но RFC 2119 указывает, что разработчикам разрешено игнорировать предложения «СЛЕДУЕТ», если у них есть для этого веские основания. Скорее всего , клиент делает нарушает спецификацию , если он предполагает , что изменение тела GET будет не изменит ответ.
Emil Lundberg 10.12.2015 11:03:00
RFC2616, называемый «HTTP / 1.1 spec», теперь устарел. В 2014 году он был заменен RFC 7230-7237. Цитата " тело сообщения ДОЛЖНО игнорироваться при обработке запроса " была удалена . Теперь это просто « Запрос на создание кадра не зависит от семантики метода, даже если метод не определяет какое-либо использование для тела сообщения ». Вторая цитата « Метод GET означает получение любой информации ... идентифицированной по Request-URI » был удален . Итак, предлагаю отредактировать ответ @Jarl
Artem Nakonechny 4.11.2016 21:47:38
Я знаю, что это старая нить - я наткнулся на нее. @Artem Nakonechny технически прав, но в новой спецификации сказано: «Полезная нагрузка в сообщении запроса GET не имеет определенной семантики; отправка тела полезной нагрузки по запросу GET может привести к тому, что некоторые существующие реализации отклонят запрос». Так что это все еще не очень хорошая идея, если ее можно избежать.
fastcatch 29.09.2017 13:39:49

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

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

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

286
10.06.2009 20:53:43
Принцип робастности ошибочен. Если вы либеральны в том, что вы принимаете, вы получите дерьмо, если у вас будет какой-либо успех с точки зрения усыновления, только потому, что вы принимаете дерьмо. Это усложнит вам развитие вашего интерфейса. Просто посмотрите на HTML. Это принцип ребустности в действии.
Eugene Beresovsky 9.08.2011 01:43:50
Я думаю, что успех и широта принятия (и злоупотребления) протоколов говорит о ценности принципа надежности.
caskey 15.08.2011 03:46:46
Вы когда-нибудь пытались разобрать настоящий HTML? Самостоятельно реализовать это невозможно, поэтому почти все, включая действительно крупных игроков, таких как Google (Chrome) и Apple (Safari), не делали этого, а полагались на существующие реализации (в конце концов, все они полагались на KHTML KDE). Такое повторное использование, конечно, хорошо, но вы пытались отобразить html в приложении .net? Это кошмар, так как вам нужно либо встраивать компонент - неуправляемый - IE (или аналогичный) с его проблемами и сбоями, либо вы используете доступный (в codeplex) управляемый компонент, который даже не позволяет выбирать текст.
Eugene Beresovsky 2.09.2011 14:10:15
Спецификация HTTP не только разрешает данные тела с помощью запроса GET, но это также распространенная практика: API _search популярного механизма ElasticSearch рекомендует запросы GET с запросом, присоединенным в теле JSON. В качестве уступки неполным реализациям HTTP-клиентов здесь также разрешены запросы POST.
Christian Pietsch 25.10.2013 11:52:12
@ChristianPietsch, сегодня это обычная практика. Четыре года назад этого не было. Хотя спецификация явно позволяет клиенту необязательно включать (МОЖЕТ) объект в запрос (раздел 7), значение MAY определено в RFC2119, и прокси-сервер (дрянной) может быть совместимым со спецификацией при удалении объектов в запросах GET, в частности, до тех пор, пока не произойдет сбой, он может предоставить «ограниченную функциональность» путем пересылки заголовков запросов, а не включенной сущности. Аналогично, существует множество правил о том, какие изменения версий ДОЛЖНЫ / МОГУТ / СЛЕДУЕТ вносить при проксировании между различными уровнями протокола.
caskey 28.10.2013 21:49:29

Я бы не советовал это, это идет вразрез со стандартными методами и не предлагает так много взамен. Вы хотите сохранить тело для контента, а не вариантов.

6
10.06.2009 20:56:09

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

148
10.06.2009 21:10:50
Использование полей заголовка ETag / Last-Modified помогает в этом: при использовании «условного GET» прокси / кэши могут действовать на эту информацию.
jldupont 15.01.2010 11:42:48
@jldupont Кэши используют наличие валидаторов, чтобы знать, можно ли повторно подтвердить устаревший ответ, однако они не используются как часть первичного или вторичного ключа кэша.
Darrel Miller 26.03.2014 14:42:39
Это можно исправить с помощью контрольной суммы тела в параметре запроса
Adrian May 3.01.2020 14:33:47

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

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

Это имеет преимущество в следовании традиционному методу PRG, помогает кеширующим посредникам кэшировать результаты и т.д.

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

31
23.04.2017 08:44:41
Вы можете просто создать свой конкретный медиатип поиска. Не могли бы вы уточнить?
Piotr Dobrogost 28.09.2011 19:45:00
При этом я говорил, что вы можете создать тип мультимедиа под названием application / vnd.myCompany.search + json, который будет содержать тип шаблона поиска, который вы хотите, чтобы клиент выдал, и клиент мог затем отправить его как POST. Как я уже подчеркивал, для этого уже существует тип мультимедиа, и он называется OpenSearch. Повторное использование существующего типа мультимедиа должно выбираться вместо пользовательского маршрута, когда вы можете реализовать свой сценарий с существующими стандартами.
SerialSeb 3.10.2011 11:47:42
Это умно, но слишком сложно и неэффективно. Теперь вам нужно отправить POST с вашими критериями поиска, получить URI в качестве ответа от вашего POST, а затем отправить GET с URI критериев поиска на сервер для его получения GET критериев и отправить результат обратно вам. (За исключением того, что включение URI в URI технически невозможно, поскольку вы не можете отправить что-то, которое может быть длиной до 255 символов, в то, что может быть не более 255 символов - поэтому вам придется использовать частичный идентификатор и ваш сервер, тогда нужно знать, как разрешить URI для ваших критериев поиска
fijiaaron 30.08.2012 21:26:21

Как насчет несоответствующих закодированных base64 заголовков? "SOMETHINGAPP-Титулы: sdfSD45fdg45 / СОС"

Длина ограничения хм. Разве вы не можете сделать вашу обработку POST различать значения? Если вам нужны простые параметры, такие как сортировка, я не понимаю, почему это будет проблемой. Я думаю, это уверенность, что вы беспокоитесь.

5
15.02.2011 21:34:57
Вы можете отправить любые параметры с x-префиксом, любые ограничения на длину заголовков будут полностью произвольным ограничением сервера.
Chris Marisic 2.06.2015 21:15:00

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

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

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

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

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

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

  • XmlHTTPRequest Fiddler

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

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

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

  • апаш
  • PHP

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

  • ?
27
30.08.2012 21:48:49
Squid 3.1.6 также удаляет тела GET, когда Content-Length равен 0 или не установлен, и в противном случае отправляет обратно HTTP 411 Length Required, даже если длина установлена
rkok 6.03.2014 09:14:34
Скрипач будет, но он вас предупреждает.
toddmo 5.08.2015 21:44:52
Вы говорите, что SEARCHметод может сломаться по пути? Если прокси не понимают метод, ожидается, что они пройдут через него как есть, поэтому я не слишком уверен, почему вы думаете, что это что-то сломает ...
Alexis Wilke 7.12.2018 20:03:58

Если вы действительно хотите отправить кэшируемое тело JSON / XML в веб-приложение, единственное разумное место для размещения ваших данных - это строка запроса, закодированная с помощью RFC4648: кодировка Base 64 с URL-адресом и безопасным алфавитом имени файла . Конечно, вы можете просто кодировать JSON и указывать в параметре URL, но Base64 дает меньший результат. Имейте в виду, что существуют ограничения размера URL-адреса, см. Какова максимальная длина URL-адреса в разных браузерах? ,

Вы можете подумать, что =символ дополнения Base64 может быть плохим для значения параметра URL, однако это не так - см. Это обсуждение: http://mail.python.org/pipermail/python-bugs-list/2007-Feb February/037195.html . Однако не следует помещать закодированные данные без имени параметра, поскольку закодированная строка с отступом будет интерпретироваться как ключ параметра с пустым значением. Я бы использовал что-то вроде ?_b64=<encodeddata>.

8
23.05.2017 12:10:54
Я думаю, что это довольно плохая идея :) Но если бы я сделал что-то подобное, я бы вместо этого использовал собственный HTTP-заголовок (и удостоверился, что я всегда отправляю обратно Vary: в ответе).
Evert 18.02.2013 16:25:04
Плохо или нет, но выполнимо :) С данными в заголовке существует аналогичная проблема с размером данных, см. Stackoverflow.com/questions/686217/… . Однако спасибо за упоминание Varyзаголовка, я не знал о его реальном потенциале.
gertas 18.02.2013 21:36:03

ИМХО, вы можете просто отправить JSONзакодированное (то есть. encodeURIComponent) В URL, таким образом, вы не нарушите HTTPспецификации и получите свой JSONна сервер.

3
27.04.2015 19:18:59
да, но главная проблема заключается в ограничении длины, как мы с этим справимся?
Sebas 28.03.2017 10:35:11

Ни консоль 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 и хоста.

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

71
27.03.2013 10:41:38
Paw также имеет опцию для поддержки запросов GET с телами, но она должна быть включена в настройках.
s.Daniel 7.01.2015 18:14:31
«Метод GET означает получение любой информации (в форме объекта), идентифицируемой посредством Request-URI». Тогда, технически незаконно / неправильно иметь конечную точку GET, которая получает все сущности? Например, GET /contacts/100/addressesвозвращает коллекцию адресов для человека с id=100.
Josh M. 7.07.2016 19:21:58
Успокоенная библиотека Java для тестирования API REST не поддерживает GET-запрос с телом. Apache HttpClient также не поддерживает его.
Paulo Merson 5.09.2016 18:33:28
Джанго также поддерживает разбор GET-тела
Bruno Finger 21.03.2019 12:13:13

Какой сервер проигнорирует это? - fijiaaron 30 августа '12 в 21:27

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

Попробуйте сами с помощью простого netcat:

$ 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 с сущностью body.

22
29.06.2013 21:26:20
Этот пример не имеет смысла, потому что обычно, когда люди собираются добавлять тело к GETзапросам, это потому, что их собственный сервер может обработать это. Таким образом, вопрос заключается в том, будут ли другие «движущиеся части» (браузеры, кэши и т. Д.) Работать правильно.
Pacerier 19.04.2016 01:56:18
Это плохие запросы, потому что ваша полезная нагрузка не ожидается (или не имеет смысла) для GET этой конкретной конечной точки - это не имеет ничего общего с использованием GETв общем случае. Случайная полезная нагрузка может POSTтак же легко прервать и вернуть то же самое 400 Bad Request, если содержимое не было в формате, который имел смысл в контексте конкретного запроса.
nobar 22.09.2018 16:13:53
И не только на этой конечной точке в целом, а скорее на этом конкретном URL .
Lawrence Dol 5.02.2019 21:42:25
Это не имеет значения, потому что это просто реализация сервера Google по этому URL. Так что нет никакого смысла в вопросе
Joel Duckworth 22.04.2019 23:21:27
для меня это было полезно, так как я пытался использовать функции firebase с запросом get + body, и эта ошибка может быть очень загадочной и трудной для понимания.
scrimau 5.11.2019 09:40:57

Elasticsearch принимает запросы GET с телом. Даже кажется, что это предпочтительный способ: Elasticsearch guide

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

58
11.11.2019 06:39:26
Было интересно, почему Elasticsearch позволяет это. Это означает, что этот запрос для подсчета всех документов с полезной нагрузкой в ​​запрос GET curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' эквивалентен включению полезной нагрузки в качестве sourceпараметра: curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
arun 11.12.2014 14:31:05
Сложные запросы могут достигать максимальной длины заголовка http.
s.Daniel 7.01.2015 17:45:55
Именно чтение документации по
PatrickWalker 19.01.2016 13:59:53
Это даже не должен быть сложный запрос. Даже простая прокрутка может вернуть очень длинный scroll_id (в кластере с большим количеством шардов), который приведет к превышению максимальной длины URL, если он там будет добавлен.
Brent Hronik 27.07.2016 19:49:34
Elasticsearch поддерживает тот же запрос, используя POST. Они только решили разрешить тело в GET, потому что они чувствовали, что GET является более семантически правильным, чем POST, когда дело доходит до запроса данных. Забавно, что Elasticsearch так много упоминается в этой теме. Я не стал бы использовать один пример (хотя и из популярного продукта) в качестве причины для следования практике.
DSO 1.07.2017 20:11:35

Я расстроен, что REST как протокол не поддерживает ООП и Getметод является доказательством. В качестве решения вы можете сериализовать ваш DTO в JSON, а затем создать строку запроса. На стороне сервера вы сможете десериализовать строку запроса в DTO.

Посмотрите на:

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

Платформа Nelibur Web Service предоставляет функциональность, которую вы можете использовать

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D
4
10.02.2014 09:07:56
Вы должны просто использовать POST. Если в URL-адресе есть имя метода, вы нарушаете основную схему остальных. Это RPC, используйте POST.
Evert 10.02.2014 15:40:44
Я не думаю, что это имеет большое значение, у нас больше проблем во время разработки с RESTful url (т.е. orders / 1). Что касается меня, то что-то не так с методом Get, это несовместимо с ООП. И кого волнует, как выглядит url :) Но с помощью подхода, основанного на сообщениях, мы можем создать стабильный удаленный интерфейс, и это действительно важно. PS это не RPC, это основано на сообщениях
GSerjo 10.02.2014 17:41:51
Я думаю, что вы упускаете весь смысл REST. Когда вы говорите, кто заботится о том, как выглядит URL, хорошо, REST заботится, очень. И почему REST совместим с ООП?
shmish111 18.12.2015 13:53:06
Нет, я просто не вижу немного дальше
GSerjo 18.12.2015 14:57:16

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

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

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

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

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

18
6.03.2014 21:44:45
Раздел 9.5 , «POST», также не упоминает тела запросов, поэтому эта логика ошибочна.
CarLuva 20.06.2014 13:40:07
@CarLuva В разделе POST написано «Метод POST используется для запроса, чтобы исходный сервер принял вложенную сущность ...» В разделе тела сущности написано «Тело сущности получено из тела сообщения ...» Следовательно, Раздел POST упоминает тело сообщения, хотя и косвенно, ссылаясь на тело объекта, которое переносится телом сообщения запроса POST.
frederickf 8.08.2014 23:14:17

Например, он работает с Curl, Apache и PHP.

PHP-файл:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

Консольная команда:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

Вывод:

GET
{"the": "body"}
4
20.11.2015 22:16:01
Веселый эксперимент! PHP будет читать только $_POSTтогда, когда тело отправлено с запросом POST и application/x-www-form-urlencoded. Это означает, что тело игнорируется в GETзапросе. В этом случае: $_GETи $_POSTв любом случае очень вводит в заблуждение. Так что лучше использоватьphp://input
Martin Muzatko 13.12.2018 14:49:51

Согласно XMLHttpRequest, это недействительно. Из стандарта :

4.5.6 send()Способ

client . send([body = null])

Инициирует запрос. Необязательный аргумент предоставляет тело запроса. Аргумент игнорируется, если метод запроса равен GETили HEAD.

Выдает InvalidStateErrorисключение, если либо состояние не открыто, либо установлен send()флаг.

Метод должен выполнить следующие действия:send(body)

  1. Если состояние не открыто , выведите InvalidStateErrorисключение.
  2. Если send()флаг установлен, выведите InvalidStateErrorисключение.
  3. Если метод запроса равен GETили HEAD, установите для тела значение null.
  4. Если тело пусто, переходите к следующему шагу.

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

Итак, если вы используете XMLHttpRequest браузера, скорее всего, он не будет работать.

9
4.05.2016 20:51:46
понижен в связи с тем, что XMLHttpRequest является реализацией. Это может не отражать фактическую спецификацию, которую предполагается реализовать.
floum 20.07.2018 15:01:15
Упомянутое выше неверно, если некоторые реализации не поддерживают отправку тела с GET, то это может быть причиной, по которой это не нужно делать, независимо от спецификации. Я действительно столкнулся с этой проблемой в кроссплатформенном продукте, над которым я работаю - только платформа, использующая XMLHttpRequest, не смогла отправить запрос get.
pjcard 10.10.2018 10:29:48

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

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

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

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

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

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

Итак, в заключение, не делайте этого.

20
20.08.2018 03:21:37

У вас есть список опций, которые намного лучше, чем использование тела запроса с GET.

Предположим, у вас есть категории и предметы для каждой категории. Оба идентифицируются по идентификатору ("catid" / "itemid" для примера). Вы хотите отсортировать по другому параметру «sortby» в определенном «порядке». Вы хотите передать параметры для «sortby» и «order»:

Вы можете:

  1. Используйте строки запроса, например example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Используйте mod_rewrite (или аналогичный) для путей: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Используйте отдельные заголовки HTTP, которые вы передаете с запросом
  4. Используйте другой метод, например POST, для извлечения ресурса.

У всех есть свои недостатки, но они намного лучше, чем использование GET с телом.

2
25.04.2019 13:51:17

Даже если популярный инструмент использует это, как часто цитируется на этой странице, я думаю, что это все еще довольно плохая идея, будучи слишком экзотическим, несмотря на то, что он не запрещен спецификацией.

Многие промежуточные инфраструктуры могут просто отклонять такие запросы.

К примеру, забудьте об использовании некоторых из доступных CDN в передней части вашего веб - сайта, как этот один :

Если GETзапрос средства просмотра включает тело, CloudFront возвращает код состояния HTTP 403 (Запрещено) для средства просмотра.

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

0
3.10.2019 09:10:50

Я использую RestTemplate Spring Framework в своей клиентской программе, и на стороне сервера я определил запрос GET с телом Json. Моя основная цель та же, что и у вас: когда в запросе есть множество параметров, их размещение в теле кажется более аккуратным, чем в длинной строке URI. Да?

Но, к сожалению, это не работает! На стороне сервера возникло следующее исключение:

org.springframework.http.converter.HttpMessageNotReadableException: отсутствует обязательное тело запроса ...

Но я почти уверен, что тело сообщения правильно предоставлено моим клиентским кодом, так что не так?

Я проследил в метод RestTemplate.exchange () и обнаружил следующее:

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

Обратите внимание, что в методе executeInternal () входной аргумент 'bufferedOutput' содержит тело сообщения, предоставленное моим кодом. Я видел это через отладчик.

Однако из-за prepareConnection () метод getDoOutput () в executeInternal () всегда возвращает false, что, в свою очередь, делает bufferedOutput полностью игнорируемым! Он не копируется в выходной поток.

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

Это пример шаблона RestTemplate среды Spring. Дело в том, что даже если тело сообщения больше не запрещено спецификацией HTTP, некоторые клиентские или серверные библиотеки или инфраструктуры могут по-прежнему соответствовать старой спецификации и отклонять тело сообщения из запроса GET.

0
17.11.2019 21:07:24
Вы не правильно читаете спецификацию или комментарии. Клиенты и серверы, отбрасывающие тело запроса, находятся в пределах спец. Не используйте GET тела запросов.
Evert 18.11.2019 22:24:26
@ Я не правильно прочитал комментарии или нет? :) Если вы прокрутите до ответа Пола Моргана (самый популярный ответ) и внимательно прочитаете комментарии, вы обнаружите следующее: «RFC2616, называемый« HTTP / 1.1 spec », теперь устарел. В 2014 году его заменили на RFCs 7230-7237. Цитата «тело сообщения ДОЛЖНО игнорироваться при обработке запроса» была удалена. Теперь это просто «Фрейм сообщения запроса не зависит от семантики метода, даже если метод не определяет какого-либо использования для тела сообщения ... "
Zhou 20.11.2019 10:45:07
@Evert Более того, я использовал утилиту тестирования REST «уверен», чтобы протестировать свой бэкэнд Spring-boot. И на стороне сервера, и на Spring-boot сохраняли тело Json для запроса GET! Только RestTemplate Sping-framework удаляет тело из запросов GET, поэтому Spring-boot, rest-assured и RestTemplate, что является / не так?
Zhou 20.11.2019 10:50:52
@Evert Последнее, но не сдача в аренду, я не призывал людей использовать body в GET-запросах, напротив, я предлагал НЕ делать этого, анализируя исходный код RestTemplate Sping-фреймворка, так почему вы отказались от моего голосования? ответ?
Zhou 20.11.2019 10:54:23
Я не понизил ваш ответ. Я просто уточняю, что любая реализация HTTP, отбрасывающая GET-запрос, находится в спецификации.
Evert 20.11.2019 12:03:42