Я разрабатываю новый веб-сервис RESTful для нашего приложения.
При выполнении GET для определенных объектов клиенты могут запрашивать содержимое объекта. Если они хотят добавить некоторые параметры (например, сортировать список), они могут добавить эти параметры в строку запроса.
В качестве альтернативы я хочу, чтобы люди могли указывать эти параметры в теле запроса. HTTP / 1.1 явно не запрещает это. Это позволит им указать больше информации, может упростить указание сложных запросов XML.
Мои вопросы:
- Это хорошая идея в целом?
- Будут ли у HTTP-клиентов проблемы с использованием тел запросов в GET-запросе?
Ответы:
Комментарий Роя Филдинга о включении тела в запрос GET .
Да, вы можете отправить тело запроса с помощью GET, но оно не должно иметь никакого значения. Если вы придаете ему значение, анализируя его на сервере и изменяя свой ответ на основе его содержимого , то вы игнорируете эту рекомендацию в спецификации HTTP / 1.1, раздел 4.3 :
И описание метода GET в спецификации HTTP / 1.1, раздел 9.3 :
в котором говорится, что тело запроса не является частью идентификации ресурса в запросе GET, а только URI запроса.
Обновление RFC2616, упоминаемый как «HTTP / 1.1 spec», теперь устарело. В 2014 году он был заменен RFC 7230-7237. Цитата "тело сообщения ДОЛЖНО игнорироваться при обработке запроса" была удалена. Теперь это просто «Запрос на создание кадра не зависит от семантики метода, даже если метод не определяет никакого использования для тела сообщения». Вторая цитата: «Метод GET означает получение любой информации ... идентифицированной по Request-URI» был удален - из комментария
источник
Хотя вы можете сделать это, поскольку это явно не исключено спецификацией HTTP, я бы посоветовал избегать этого просто потому, что люди не ожидают, что все будет работать именно так. В цепочке HTTP-запросов есть много этапов, и хотя они «в основном» соответствуют спецификации HTTP, единственное, что вы уверены, это то, что они будут вести себя так, как традиционно используются веб-браузерами. (Я имею в виду такие вещи, как прозрачные прокси, ускорители, A / V инструментарий и т. Д.)
Этот принцип лежит в основе принципа надежности: «будьте либеральными в том, что вы принимаете, и консервативными в том, что вы отправляете», вы не хотите выходить за пределы спецификации без уважительной причины.
Однако, если у вас есть веская причина, сделайте это.
источник
Скорее всего, вы столкнетесь с проблемами, если когда-нибудь попробуете воспользоваться кешированием. Прокси не будут искать в теле GET, чтобы увидеть, влияют ли параметры на ответ.
источник
Ни консоль restclient, ни консоль REST не поддерживают это, но curl поддерживает.
Спецификация HTTP говорится в разделе 4.3
Раздел 5.1.1 перенаправляет нас в раздел 9.x для различных методов. Ни один из них явно не запрещает включение тела сообщения. Однако...
Раздел 5.2 говорит
и раздел 9.3 говорит
Что вместе указывает на то, что при обработке запроса GET серверу не требуется проверять что-либо, кроме поля заголовка Request-URI и хоста.
Таким образом, спецификация HTTP не мешает вам отправлять тело сообщения с помощью GET, но существует достаточно двусмысленности, чтобы меня не удивило, если бы она не поддерживалась всеми серверами.
источник
GET /contacts/100/addresses
возвращает коллекцию адресов для человека сid=100
.Elasticsearch принимает запросы GET с телом. Даже кажется, что это предпочтительный способ: Elasticsearch guide
Некоторые клиентские библиотеки (например, драйвер Ruby) могут регистрировать команду cry в stdout в режиме разработки, и он широко использует этот синтаксис.
источник
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'
То, чего вы пытаетесь достичь, уже давно было сделано с помощью гораздо более распространенного метода, который не использует полезную нагрузку с GET.
Вы можете просто создать свой конкретный медиатип поиска или, если вы хотите быть более RESTful, использовать что-то вроде OpenSearch и отправить запрос в URI, указанный сервером, например, / search. Затем сервер может сгенерировать результат поиска или построить окончательный URI и перенаправить с помощью 303.
Это имеет преимущество в следовании традиционному методу PRG, помогает кеширующим посредникам кэшировать результаты и т. Д.
Тем не менее, URI в любом случае кодируются для всего, что не является ASCII, как и application / x-www-form-urlencoded и multipart / form-data. Я бы рекомендовал использовать это, а не создавать еще один пользовательский формат json, если вы намерены поддерживать сценарии ReSTful.
источник
Вы можете отправить GET с телом или отправить POST и отказаться от RESTish религиозности (это не так уж и плохо, 5 лет назад в этой вере был только один член - его комментарии связаны выше).
Не являются хорошими решениями, но отправка тела GET может предотвратить проблемы для некоторых клиентов - и некоторых серверов.
Выполнение POST может иметь препятствия с некоторыми средами RESTish.
Джулиан Решке предложил выше использовать нестандартный HTTP-заголовок, такой как «SEARCH», который может быть элегантным решением, за исключением того, что он еще менее вероятно будет поддерживаться.
Может оказаться наиболее продуктивным перечислить клиентов, которые могут и не могут выполнять все вышеперечисленное.
Клиенты, которые не могут отправить GET с телом (о котором я знаю):
Клиенты, которые могут отправить GET с телом:
Серверы и библиотеки, которые могут получить тело из GET:
Серверы (и прокси), которые снимают тело с GET:
источник
SEARCH
метод может сломаться по пути? Если прокси не понимают метод, ожидается, что они пройдут через него как есть, поэтому я не слишком уверен, почему вы думаете, что это что-то сломает ...Google, например, делает хуже, чем игнорирует его, он будет считать это ошибкой !
Попробуйте сами с помощью простого netcat:
(за содержимым 1234 следует CR-LF, то есть всего 6 байтов)
и вы получите:
Вы также получаете 400 плохих запросов от Bing, Apple и т. Д., Которые обслуживаются AkamaiGhost.
Поэтому я бы не советовал использовать GET-запросы с сущностью тела.
источник
GET
запросам, это потому, что их собственный сервер может обработать это. Таким образом, вопрос заключается в том, будут ли другие «движущиеся части» (браузеры, кэши и т. Д.) Работать правильно.GET
этой конкретной конечной точки - это не имеет ничего общего с использованиемGET
в общем случае. Случайная полезная нагрузка можетPOST
так же легко прервать и вернуть то же самое400 Bad Request
, если содержимое не было в формате, который имел смысл в контексте конкретного запроса.Я поставил этот вопрос в IETF HTTP WG. Комментарий Роя Филдинга (автора документа http / 1.1 в 1998 году) заключался в том, что
RFC 7213 (HTTPbis) заявляет:
Теперь очевидно, что предполагалось, что семантическое значение в телах запросов GET запрещено, что означает, что тело запроса не может использоваться для воздействия на результат.
Существуют прокси-серверы, которые определенным образом нарушат ваш запрос, если вы включите тело в GET.
Итак, в заключение, не делайте этого.
источник
Из RFC 2616, раздел 4.3 , «Тело сообщения»:
То есть серверы всегда должны читать любое предоставленное тело запроса из сети (проверьте Content-Length или прочитайте разделенное тело и т. Д.). Кроме того, прокси-серверы должны пересылать любое такое тело запроса, которое они получают. Затем, если RFC определяет семантику для тела для данного метода, сервер может фактически использовать тело запроса при генерации ответа. Однако, если RFC не определяет семантику для тела, то сервер должен игнорировать это.
Это соответствует цитате из Филдинга выше.
Раздел 9.3 , «GET», описывает семантику метода GET и не упоминает тела запросов. Следовательно, сервер должен игнорировать любое тело запроса, которое он получает по запросу GET.
источник
Согласно XMLHttpRequest, это недействительно. Из стандарта :
Хотя я не думаю, что так должно быть, потому что для запроса GET может потребоваться большой объем содержимого
Итак, если вы используете XMLHttpRequest браузера, скорее всего, он не будет работать.
источник
Если вы действительно хотите отправить кэшируемое тело JSON / XML в веб-приложение, единственное разумное место для размещения ваших данных - это строка запроса, закодированная с помощью RFC4648: кодировка Base 64 с URL-адресом и безопасным алфавитом имени файла . Конечно, вы могли бы просто urlencode JSON и указать значение параметра URL, но Base64 дает меньший результат. Имейте в виду, что существуют ограничения размера URL-адреса, см. Какова максимальная длина URL-адреса в разных браузерах? ,
Вы можете подумать, что
=
символ дополнения Base64 может быть плохим для значения параметра URL, однако это не так - смотрите это обсуждение: http://mail.python.org/pipermail/python-bugs-list/2007-Feb February/037195.html . Однако не следует помещать закодированные данные без имени параметра, поскольку закодированная строка с отступом будет интерпретироваться как ключ параметра с пустым значением. Я бы использовал что-то вроде?_b64=<encodeddata>
.источник
Vary
заголовка, я не знал о его реальном потенциале.Я бы не советовал это, это идет вразрез со стандартными методами и не предлагает так много взамен. Вы хотите сохранить тело для контента, а не вариантов.
источник
Как насчет несоответствующих закодированных base64 заголовков? "SOMETHINGAPP-Титулы: sdfSD45fdg45 / СОС"
Длина ограничения хм. Разве вы не можете сделать вашу обработку POST различать значения? Если вам нужны простые параметры, такие как сортировка, я не понимаю, почему это будет проблемой. Я думаю, это уверенность, что вы беспокоитесь.
источник
x-
префиксом, любые ограничения на длину заголовков будут полностью произвольным ограничением сервера.Я расстроен, что REST как протокол не поддерживает ООП и
Get
метод является доказательством. В качестве решения вы можете сериализовать ваш DTO в JSON, а затем создать строку запроса. На стороне сервера вы сможете десериализовать строку запроса в DTO.Посмотрите на:
Подход, основанный на сообщениях, может помочь решить проблему ограничения метода Get. Вы можете отправить любой DTO, как с телом запроса
Платформа веб-сервиса Nelibur предоставляет функциональность, которую вы можете использовать
источник
Например, он работает с Curl, Apache и PHP.
PHP-файл:
Консольная команда:
Вывод:
источник
$_POST
тогда, когда тело отправлено с запросом POST иapplication/x-www-form-urlencoded
. Это означает, что тело игнорируется вGET
запросе. В этом случае:$_GET
и$_POST
в любом случае очень вводит в заблуждение. Так что лучше использоватьphp://input
ИМХО, вы можете просто отправить
JSON
закодированное (то есть.encodeURIComponent
) ВURL
, таким образом, вы не нарушитеHTTP
спецификации и получите свойJSON
на сервер.источник
У вас есть список опций, которые намного лучше, чем использование тела запроса с GET.
Предположим, у вас есть категории и предметы для каждой категории. Оба идентифицируются по идентификатору ("catid" / "itemid" для примера). Вы хотите отсортировать по другому параметру sortby в определенном порядке. Вы хотите передать параметры для «sortby» и «order»:
Вы можете:
example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
example.com/category/{catid}/item/{itemid}/{sortby}/{order}
У всех есть свои недостатки, но они намного лучше, чем использование GET с телом.
источник
Даже если популярный инструмент использует это, как часто цитируется на этой странице, я думаю, что это все еще довольно плохая идея, будучи слишком экзотическим, несмотря на то, что он не запрещен спецификацией.
Многие промежуточные инфраструктуры могут просто отклонять такие запросы.
К примеру, забудьте об использовании некоторых из доступных CDN в передней части вашего веб - сайта, как этот один :
И да, ваши клиентские библиотеки также могут не поддерживать отправку таких запросов, как указано в этом комментарии .
источник
Я использую RestTemplate среды Spring в моей клиентской программе и на стороне сервера я определил запрос GET с телом Json. Моя основная цель такая же, как и у вас: когда в запросе есть множество параметров, их размещение в теле кажется более аккуратным, чем в длинной строке URI. Да?
Но, к сожалению, это не работает! На стороне сервера возникло следующее исключение:
org.springframework.http.converter.HttpMessageNotReadableException: отсутствует обязательное тело запроса ...
Но я почти уверен, что тело сообщения правильно предоставлено моим клиентским кодом, так что не так?
Я проследил в метод RestTemplate.exchange () и обнаружил следующее:
Обратите внимание, что в методе executeInternal () входной аргумент 'bufferedOutput' содержит тело сообщения, предоставленное моим кодом. Я видел это через отладчик.
Однако из-за prepareConnection () getDoOutput () в executeInternal () всегда возвращает false, что, в свою очередь, делает bufferedOutput полностью игнорируемым! Он не копируется в выходной поток.
Следовательно, моя серверная программа не получила тела сообщения и вызвала это исключение.
Это пример шаблона RestTemplate среды Spring. Дело в том, что даже если тело сообщения больше не запрещено спецификацией HTTP, некоторые клиентские или серверные библиотеки или инфраструктуры могут по-прежнему соответствовать старой спецификации и отклонять тело сообщения из запроса GET.
источник