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

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

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

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

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

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

Мои вопросы:

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

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

Ответы [ 18 ]

7 голосов
/ 04 мая 2016

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

4.5.6 send() метод

<i>client</i> . send([<i>body</i> = null])

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

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

Метод send(<i>body</i>) должен выполнить следующие шаги:

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

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

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

7 голосов
/ 18 февраля 2013

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

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

5 голосов
/ 21 ноября 2015

Например, он работает с 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 голосов
/ 10 февраля 2014

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

Взгляните на:

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

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

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 голосов
/ 26 февраля 2013

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

4 голосов
/ 16 февраля 2011

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

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

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

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

0 голосов
/ 25 апреля 2019

У вас есть список опций, которые намного лучше, чем использование тела запроса с 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 с телом.

...