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, спеціальним чином, щоб користувач ознайомився з тим, що вимагається можлива небезпечна дія.

...

Методи також можуть мати властивість "idempotence", оскільки (окрім помилок чи проблем із закінченням терміну дії) побічні ефекти N> 0 однакових запитів такі ж, як і для одного запиту. Методи GET, HEAD, PUT та DELETE поділяють цю властивість. Крім того, методи ВАРІАНТИ та ТРЕБА НЕ повинні мати побічних ефектів, і вони по суті є безсильними.


11
Навіщо взагалі використовувати POST, якщо ви не збираєтесь надавати дані в організмі?
Сонячний Міленов

114
Тому що операція не є безсильною.
Стівен Ювіг

20
@Jred, зауважте, що слово "REST" не з'являється в цьому питанні з 2,5 років тому. :) Специфікація HTTP про ідентифікацію застосовується незалежно від архітектури аромату місяця для веб-служб. На щастя, система, для якої цей API призначений для проксі-сервера, все одно застаріла.
Стівен Ювіг

5
Оскільки журнали серверів не записують параметри POST, але вони записують рядки запитів. Набагато простіше запустити серію запитів без інструментації її в браузері, а потім подивитись на прослідку, ніж натискати на них. Також API був не браузер-сервер, а швидше сервер-сервер. Найголовніше, що вся справа була все-таки консервована. :)
Стівен Ювіг

13
Для всіх, хто не знає, що означає idempotent: | restapitutorial.com/lessons/idempotency.html
Крістофер Грігг

Відповіді:


259

Якщо ваша дія не є ідентичною, тоді ви ОБОВ'ЯЗКОВО використовувати 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, тому сервер буде мати той самий стан, але відповідь буде іншим. Дивіться зображення корови: restapitutorial.com/lessons/idempotency.html
JPK

131

Усі праві: дотримуйтесь 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 - це тип вмісту, який вони розміщують, то слід дотримуватися правил цього типу Content-Type. А правила для 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 Подання форми


10
Це гідний аргумент, але я вважаю, що сучасні реалізації JavaScript в браузері роблять це суперечливим моментом. Я подумаю про це, хоча - це переконливо в майбутньому захищеному вигляді. Тільки тому, що зараз я не використовую форму, це не означає, що я не хочу пізніше.
Стівен Ювіг

9
Змішування GET з POST - це дійсно погана ідея - жахливо зламати HTTP і без поважних причин.
aehlke

6
Цей фрагмент не відображається на сторінці, на яку ви пов’язані
Гарет

40
Правильно, але атрибут методу просто визначає, як "набір даних форми" включається в запит. Коли значення methodPOST, немає згадки про зміну URI у формі action. І будь-який URI, звичайно, вже може містити частину рядка запиту.
Гарет

16
@Powerlord Це просто неправильно. Спробуйте встановити форму для POST з дією, наприклад, /Books?bookCode=1234. Веб-сервер отримає варшоти форми POST та рядок запиту.
Їжак

9

З програмної точки зору, для клієнта він упаковує параметри та додає їх до URL-адреси та проводить POST проти GET. На стороні сервера він оцінює вхідні параметри з рядка запиту замість розміщених байтів. В основному, це миття.

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

Тим не менш, з точки зору програміста, я вважаю за краще дозволити або POST з усіма параметрами в тілі, або GET з усіма парамами URL-адреси, і явно ігнорувати параметри URL-адреси з будь-яким запитом POST. Це дозволяє уникнути плутанини.


8

Я б подумав, що все-таки може бути досить РЕЗУЛЬТАТИВним мати аргументи запитів, які ідентифікують ресурс у URL-адресі, зберігаючи при цьому корисну навантаження вмісту, обмежене тілом POST. Здається, це розділяє міркування "Що я надсилаю?" проти "Кому я надсилаю його?".


5
Питання було не про REST.
Стівен Ювіг

3
@ user359996 Не всі HTTP API є RESTful. Насправді, більшість API, які стверджують, що насправді це не так. Також цікавий факт, що REST також не є лише HTTP.
Алек Мев

4

REST табір мають деякі керівні принципи , які ми можемо використовувати для стандартизації , як ми використовуємо HTTP дієслова. Це корисно при створенні API RESTful, як ви робите.

Коротше кажучи: GET має бути лише для читання, тобто не мати впливу на стан сервера. POST використовується для створення ресурсу на сервері. PUT використовується для оновлення або створення ресурсу. DELETE використовується для видалення ресурсу.

Іншими словами, якщо ваша дія API змінює стан сервера, REST радить нам використовувати POST / PUT / DELETE, але не GET.

Користувальницькі агенти зазвичай розуміють, що робити декілька постів POST - це погано, і вони застерігають від цього, оскільки мета POST полягає у зміні стану сервера (наприклад, оплата товарів при оформленні замовлення), і ви, ймовірно, не хочете цього робити двічі!

Порівняйте з GET, який ви можете робити часто, як вам подобається (idempotent).


13
У таборі REST кажуть, що ви повинні використовувати HTTP, визначений у специфікації HTTP. тобто RFC2616 Нічого більше, нічого менше.
Даррел Міллер

1
@Darrel Посилання на ibm.com/developerworks/webservices/library/ws-restful : REST просить розробників використовувати методи HTTP явно і таким чином, що відповідає визначенню протоколу. Цей базовий принцип проектування REST встановлює індивідуальне відображення між операціями створення, читання, оновлення та видалення (CRUD) та методами HTTP. Відповідно до цього відображення: Щоб створити ресурс на сервері, використовуйте POST. Щоб отримати ресурс, використовуйте GET. Щоб змінити стан ресурсу або оновити його, використовуйте PUT. Щоб видалити або видалити ресурс, використовуйте DELETE.
saille

5
Вибачте, але це просто неправильно. REST вимагає дотримання єдиного інтерфейсу. Якщо ви використовуєте HTTP, то цей рівномірний інтерфейс частково визначений RFC 2616. У цій специфікації не існує індивідуального зіставлення між методами створення, читання, оновлення та видалення та методами HTTP.
Даррел Міллер

3
Отримати та видалити карту досить добре для читання та видалення в CRUD, але використання PUT / POST для оновлення та створення не настільки прямо. Див stackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw

5
Озираючись на це 6 років пізніше і враховуючи, що питання було переглянуто ~ 100 тис. Разів, я вважаю, що варто переглянути невелике оновлення. Даррел правильний згідно з визначенням Fielding REST ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - не згадується відображення HTPS- дієслів до CRUD. Поради розробників IBM (посилання у коментарі вище) відображає загальну практику впровадження API RESTful, а не визначення REST Fielding.
saille

-13

Я погоджуюся - напевно безпечніше використовувати запит GET, якщо ви просто передаєте дані в URL-адресі, а не в тілі. Дивіться подібне запитання для отримання додаткових поглядів на всю концепцію POST + GET.


17
Якщо операція має побічні ефекти, то використовувати метод GET, безумовно, не є «безпечнішим», оскільки браузер передбачає, що всі GET є ідентичними.
dcstraw

Пошукові системи також перетворюють це в кошмар, оскільки Google спокійно "натисне" на всі посилання з GET-запитом, але опустить усе інше. Вихід із сервісу не настільки безпечний, щоб невинний сканер може випадково витерти базу даних.
Алехандро
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.