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



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



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



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



мои вопросы:




  • это вообще хорошая идея?

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


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

1099   17  

17 ответов:

Рой Филдинг комментарий по этому поводу, в том числе тела сделать запрос.

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

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

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

....Рой

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

[...] если метод запроса не включает определенную семантику для объекта-тела, то тело сообщения должны игнорируется при обработке запроса.

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

метод GET означает получение любой информации ([...]) идентифицируется с помощью Запрос URI.

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

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

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

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

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

ни restclient, ни REST console поддержка этого, но curl делает.

The спецификация HTTP написано в разделе 4.3

тело сообщения не должно включаться в запрос, если спецификация метода запроса (раздел 5.1.1) не позволяет отправлять тело сущности в запросах.

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

5.2 говорит

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

и 9.3 говорит

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

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

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

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

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

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

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

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

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

какой сервер будет игнорировать его? - 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 с сущностью тела.

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

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

выполнение сообщения может иметь препятствия с некоторыми рамками RESTish.

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

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

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

  • Запрос Скрипач

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

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

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

  • Apache
  • PHP

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

  • ?

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

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

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

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

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

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

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

RFC 7213 (HTTPbis) состояния:

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

теперь кажется ясным, что намерение было семантическим значение на GET request bodies запрещено, что означает, что тело запроса не может быть использовано для влияния на результат.

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

Итак, вкратце, не делайте этого.

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

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

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

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

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

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

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

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

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

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

согласно XMLHttpRequest, это недопустимо. Из стандартный:

4.5.6 в send() метод

client . send([body = null])

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

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

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

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

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

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

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

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

PHP файл:

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

Comments

    Ничего не найдено.