HTTP POST с параметрами URL-запроса - хорошая идея или нет? [закрыто]

451

Я разрабатываю API для работы с HTTP, и мне интересно, если использовать команду HTTP POST, но только с параметрами URL-запроса и без тела запроса, это хороший путь.

Соображения:

  • «Хороший веб-дизайн» требует отправки неидемпотентных действий через POST. Это неидемпотентное действие.
  • Это приложение легче разрабатывать и отлаживать, когда параметры запроса присутствуют в URL.
  • API не предназначен для широкого использования.
  • Кажется, что выполнение запроса POST без тела потребует немного больше работы, например, Content-Length: 0заголовок должен быть явно добавлен.
  • Мне также кажется, что POST без тела немного противоречит ожиданиям большинства разработчиков и HTTP-фреймворков.

Есть ли еще какие-нибудь подводные камни или преимущества для отправки параметров запроса POST через URL-запрос, а не тело запроса?

Изменить: Причина, по которой это рассматривается, заключается в том, что операции не являются идемпотентными и имеют побочные эффекты, кроме поиска. Смотрите спецификации HTTP :

В частности, было установлено, что методы GET и HEAD НЕ ДОЛЖНЫ иметь значение выполнения действия, отличного от извлечения. Эти методы следует считать «безопасными». Это позволяет пользовательским агентам представлять другие методы, такие как POST, PUT и DELETE, особым образом, чтобы пользователь знал о том, что запрашивается небезопасное действие.

...

Методы также могут иметь свойство "идемпотентности", заключающееся в том, что (кроме ошибок с ошибками или истечением срока действия) побочные эффекты от N> 0 идентичных запросов такие же, как и для одного запроса. Методы GET, HEAD, PUT и DELETE разделяют это свойство. Кроме того, методы OPTIONS и TRACE НЕ ДОЛЖНЫ иметь побочных эффектов, и поэтому являются по своей сути идемпотентными.

Стивен Хьюиг
источник
11
Зачем вообще использовать POST, если вы не собираетесь предоставлять данные в теле?
Солнечный Миленов
114
Потому что операция не идемпотентна.
Стивен Хьюиг
20
@ Джаред, обратите внимание, что слово «ОТДЫХ» в этом вопросе не фигурирует 2,5 года назад. :) Спецификация HTTP на идемпотентность применяется независимо от того, какая архитектура «вкус месяца» предназначена для веб-сервисов. К счастью, система, для которой этот API был разработан для прокси, все равно устарела.
Стивен Хувиг
5
Поскольку журналы сервера не записывают параметры POST, но они записывают строки запроса. Гораздо проще выполнить серию запросов, не обрабатывая их в браузере, а затем взглянуть на трассировку, чем на них щелкать. Также API был не браузером к серверу, а сервером к серверу. Самое главное, что все дело было консервировано в любом случае. :)
Стивен Хьюиг
13
Для тех, кто не знает, что означает идемпотент: | restapitutorial.com/lessons/idempotency.html
Кристофер Григг

Ответы:

260

Если ваше действие не идемпотентно, то вы ДОЛЖНЫ использовать POST. Если вы этого не сделаете, вы просто напрашиваетесь на неприятности в будущем. GET, PUTИ DELETEметоды требуется , чтобы быть идемпотентными. Представьте, что произойдет в вашем приложении, если клиент будет предварительно извлекать все возможные GETзапросы вашего сервиса - если это вызовет побочные эффекты, видимые для клиента, то что-то не так.

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

Думайте о части запроса URL как о команде ресурса, чтобы ограничить область действия текущего запроса. Как правило, строки запроса используются для сортировки или фильтрации GETзапроса (например ?page=1&sort=title), но я предполагаю, что имеет смысл POSTтакже ограничивать область действия (возможно, как ?action=delete&id=5).

Дон маккоги
источник
4
Я выбрал этот ответ для этого конкретного случая, но я думаю, что аргумент Р. Бемроуза убедителен для публичных API.
Стивен Хьюиг
4
Я не думаю, что его ответ является строго правильным. Если вам известны параметры URL для публикации формы, когда HTML-страница отправляется клиенту, вы можете привязать эти параметры URL к атрибуту действия формы, в противном случае JavaScript может установить параметры URL при отправке формы.
Дон МакКоги
3
как насчет публикации XML-файла на URL с параметрами запроса? это возможно?
OpenCoderX
3
Другой пример: данные запроса могут быть в объекте http, а запрошенный формат ответа передается в параметре запроса ( /action?response_format=json)
rds
4
+1 сегодня кое-что узнал. У удаления есть техническая составляющая, чтобы быть идемпотентом. Если объект действительно удален, то вы получите 404 not found, поэтому у сервера будет то же состояние, но ответ будет другим. См. Фото коровы: restapitutorial.com/lessons/idempotency.html
июля
132

Все правы: придерживайтесь POST для неидемпотентных запросов.

Как насчет использования строки запроса URI и содержимого запроса? Ну, это действительный HTTP (см. Примечание 1), так почему бы и нет ?!

Это также совершенно логично: URL-адреса, включая часть строки запроса, предназначены для поиска ресурсов. Принимая во внимание, что глаголы метода HTTP (POST - и его необязательное содержимое запроса) предназначены для указания действий или действий с ресурсами. Это должны быть ортогональные проблемы. (Но они не являются красиво ортогональными проблемами для особого случая ContentType = application / x-www-form-urlencoded, см. Примечание 2 ниже.)

Примечание 1: спецификация HTTP (1.1) не устанавливает, что параметры и содержимое запроса являются взаимоисключающими для HTTP-сервера, который принимает запросы POST или PUT. Таким образом, любой сервер может принять оба варианта. То есть, если вы пишете сервер, ничто не мешает вам принять и то и другое (кроме, может быть, негибкой структуры). Обычно сервер может интерпретировать строки запроса в соответствии с любыми правилами. Он может даже интерпретировать их с помощью условной логики, которая ссылается и на другие заголовки, такие как Content-Type, что приводит к примечанию 2:

Примечание 2: если веб-браузер является основным способом доступа пользователей к вашему веб-приложению, а application / x-www-form-urlencoded является типом контента, который они публикуют, тогда вы должны следовать правилам для этого типа контента. А правила для application / x-www-form-urlencoded гораздо более специфичны (и, честно говоря, необычны): в этом случае вы должны интерпретировать URI как набор параметров, а не местоположение ресурса. [Это та же самая полезность, которую поднял Powerlord; что может быть трудно использовать веб-формы для размещения контента на вашем сервере. Просто объяснил немного по-другому.]

Примечание 3: для чего изначально нужны строки запроса? RFC 3986 определяет строки HTTP-запроса как часть URI, которая работает как неиерархический способ поиска ресурса.

Если читатели, задающие этот вопрос, захотят спросить, что такое хорошая архитектура RESTful: шаблон архитектуры RESTful не требует, чтобы схемы URI работали определенным образом. Архитектура RESTful связана с другими свойствами системы, такими как кэшируемость ресурсов, структура самих ресурсов (их поведение, возможности и представления), а также удовлетворяется ли идемпотентность. Или, другими словами, достижение дизайна, который очень совместим с протоколом HTTP и его набором глаголов метода HTTP. :-) (Другими словами, RESTful архитектура не очень presciptive с тем, как ресурсы расположены .)

Последнее замечание: иногда параметры запроса используются для других целей, которые не являются ни локализацией ресурсов, ни кодированием контента. Вы когда-нибудь видели параметр запроса, такой как «PUT = true» или «POST = true»? Это обходные пути для браузеров, которые не позволяют использовать методы PUT и POST. Хотя такие параметры рассматриваются как часть строки URL запроса (на проводе), я считаю , что они не являются частью запроса в URL-адресе в духе .

Тим Ловелл-Смит
источник
66

Вы хотите причины? Вот один из них:

Веб-форму нельзя использовать для отправки запроса на страницу, которая использует сочетание GET и POST. Если вы установите метод формы GET, все параметры будут в строке запроса. Если вы установите метод формы POST, все параметры будут в теле запроса.

Источник: стандарт HTML 4.01, раздел 17.13.

Powerlord
источник
10
Это достойный аргумент, но я думаю, что реализация Javascript в современном браузере делает его спорным. Я подумаю об этом, хотя - это неотразимо в плане будущего. То, что я сейчас не использую форму для этого, не означает, что я не захочу позже.
Стивен Хувиг,
9
Смешивать GET с POST - очень плохая идея - ужасно нарушать HTTP и без веской причины.
aehlke
6
Этот фрагмент не появляется на странице, на которую вы ссылаетесь
Гарет
40
Правильно, но атрибут метода просто определяет, как «набор данных формы» включается в запрос. Когда methodPOST, нет упоминания об изменении URI в форме action. И любой URI, конечно, может уже содержать часть строки запроса.
Гарет
16
@Powerlord Это просто неправильно. Попробуйте настроить форму для POST с действием, например. /Books?bookCode=1234, Веб-сервер получит переменные формы POST и строку запроса.
Jez
9

С программной точки зрения для клиента он упаковывает параметры и добавляет их в URL и проводит POST против GET. На стороне сервера он оценивает входящие параметры из строки запроса вместо отправленных байтов. По сути, это стирка.

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

Тем не менее, с точки зрения программиста, я предпочитаю разрешить либо POST со всеми параметрами в теле, либо GET со всеми параметрами в URL, и явно игнорировать параметры URL при любом запросе POST. Это позволяет избежать путаницы.

JRO
источник
8

Я думаю, что все еще может быть довольно RESTful иметь аргументы запроса, которые идентифицируют ресурс в URL, сохраняя полезную нагрузку контента, ограниченную телом POST. Казалось бы, это разделяет соображения "Что я посылаю?" против "Кому я посылаю это?"

swizzcheez
источник
5
Вопрос был не о ОТДЫХЕ.
Стивен Huwig
3
@ user359996 Не все HTTP API являются RESTful. На самом деле, большинство API, которые утверждают, что на самом деле это не так. Кроме того, забавный факт, REST также не только HTTP.
Алек
4

В лагере REST есть несколько руководящих принципов, которые мы можем использовать для стандартизации использования HTTP-глаголов. Это полезно при создании RESTful API, как вы делаете.

В двух словах: GET должен быть только для чтения, т.е. не должен влиять на состояние сервера. POST используется для создания ресурса на сервере. PUT используется для обновления или создания ресурса. DELETE используется для удаления ресурса.

Другими словами, если ваше действие API изменяет состояние сервера, REST советует нам использовать POST / PUT / DELETE, но не GET.

Пользовательские агенты обычно понимают, что выполнение нескольких POST - это плохо, и предупреждают об этом, потому что цель POST - изменить состояние сервера (например, оплатить товары при оформлении заказа), и вы, вероятно, не хотите делать это дважды!

Сравните с GET, который вы можете делать часто, как вам нравится (идемпотент).

Saille
источник
13
Лагерь REST говорит, что вы должны использовать HTTP, как определено в спецификации HTTP. т.е. RFC2616 не больше, не меньше.
Даррел Миллер
1
@Darrel Ссылаясь ibm.com/developerworks/webservices/library/ws-restful : REST просит разработчиков использовать HTTP методы явно и в способе , которым это соответствует определению протокола. Этот базовый принцип проектирования REST устанавливает взаимно-однозначное сопоставление между операциями создания, чтения, обновления и удаления (CRUD) и методами HTTP. Согласно этому отображению: Чтобы создать ресурс на сервере, используйте POST. Чтобы получить ресурс, используйте GET. Чтобы изменить состояние ресурса или обновить его, используйте PUT. Чтобы удалить или удалить ресурс, используйте DELETE.
Сэйл
5
Извините, но это просто неправильно. REST требует соответствия единому интерфейсу. Если вы используете HTTP, то этот унифицированный интерфейс частично определяется RFC 2616. В этой спецификации нет взаимно-однозначного сопоставления между методами создания, чтения, обновления и удаления и методами HTTP.
Даррел Миллер
3
ПОЛУЧИТЬ и УДАЛИТЬ сопоставление довольно хорошо для чтения и удаления в CRUD, но использование PUT / POST для обновления и создания не так просто. См stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw
5
Оглядываясь назад на это 6 лет спустя, и учитывая, что вопрос был просмотрен ~ 100 000 раз, я чувствую, что стоит добавить небольшое обновление. Даррел прав в соответствии с определением REST Филдинга ( ics.uci.edu/~fielding/pubs/dis Диссертация/rest_arch_style.htm ) - нет упоминания о сопоставлении глаголов HTTP с CRUD. Рекомендации IBM для разработчиков (ссылка в комментариях выше) отражают обычную практику реализации RESTful API, а не определение REST от Fielding.
saille
-13

Я согласен - возможно, безопаснее использовать запрос GET, если вы просто передаете данные в URL, а не в теле. Смотрите этот похожий вопрос для некоторых дополнительных взглядов на всю концепцию POST + GET.

Марк Новаковский
источник
17
Если операция имеет побочные эффекты, то, конечно, не «безопаснее» использовать метод GET, потому что браузер предполагает, что все GET являются идемпотентными.
dcstraw
Поисковые системы также преобразуют это в кошмар, потому что Google будет безопасно «кликать» по всем ссылкам с помощью запроса GET, но пропустит все остальное. Оставлять службу не так безопасно, что невинный сканер может случайно стереть базу данных.
Алехандро