Питання ВІДПОВІДАТИ ВІД ПУНКТУ В ПУНКЦІ


Відповідно до специфікації HTTP / 1.1:

The POST Метод використовується для запиту, що сервер-джерело приймає сутність, що міститься в запиті, як новий підпорядкований ресурсу, ідентифікований Request-URI в Request-Line

Іншими словами, POST використовується, щоб створити.

The PUT Метод запитує, щоб доданий об'єкт зберігався відповідно до наданого Request-URI. Якщо Request-URI відноситься до вже існуючого ресурсу, прикладений об'єкт ПОВИННІ розглядатись як модифікована версія того, що проживає на сервері походження. Якщо Request-URI не вказує на існуючий ресурс, і цей URI здатний визначати як новий ресурс запитним користувацьким агентом, сервер походження може створити ресурс з цим URI. "

Це, PUT використовується, щоб створити або оновити.

Отже, який з них слід використовувати для створення ресурсу? Або потрібно підтримувати обидва?


4468
2018-03-10 14:25


походження


Можливо, буде корисно використовувати визначення в HTTPbis - Рой поставив справжню частину роботи, щоб з'ясувати їх. Побачити: tools.ietf.org/html/... - Mark Nottingham
Просто, щоб принести @ MarkNottingham коментар до останньої редакції, ось тут POST і Випущений, як визначено на HTTPbis. - Marius Butuc
Мені здається, що ці дебати виникли з загальної практики спрощення РЕСТ, описуючи методи HTTP у термінах операцій CRUD. - Stuporman
На жаль, перші відповіді неправильні щодо POST. Перевірте мою відповідь для кращого пояснення відмінностей: stackoverflow.com/a/18243587/2458234 - 7hi4g0
PUT і POST є небезпечними методами. Проте PUT є ідемпотентним, тоді як POST - не. - Дивіться ще на: restcookbook.com/HTTP%20Methods/put-vs-post/... - Dinesh Saini


Відповіді:


Загалом: 

Обидва PUT і POST можуть бути використані для створення.

Ви повинні запитати: "Що ти робиш?" щоб розрізнити те, що ви повинні використовувати. Припустимо, ви розробляєте API для запитання. Якщо ви хочете використовувати POST, то ви зробите це зі списком питань. Якщо ви хочете використовувати PUT, то ви зробите це для конкретного питання.

Чудово обидва вони можуть бути використані, тому я повинен використовувати його в моєму RESTful дизайні:

Вам не потрібно підтримувати PUT і POST.

Котрий використовується залишається до вас. Просто пам'ятайте, як правильно використовувати відповідний об'єкт залежно від того, який об'єкт ви посилаєте на запит.

Деякі міркування:

  • Ви називаєте свої URL-адреси, які ви створюєте явно, або дозволити серверу вирішити? Якщо ви називаєте їх, то використовуйте PUT. Якщо ви дозволите серверу вирішити, використовуйте POST.
  • PUT є ідемпотентом, тому, якщо ви двічі вкладете об'єкт, він не має ефекту. Це хороша властивість, тому я, можливо, буду використовувати PUT.
  • Ви можете оновити або створити ресурс з PUT з тією ж URL-адресою об'єкта
  • За допомогою POST ви можете одержати 2 запити, одночасно внесення змін до URL-адреси, і вони можуть оновлювати різні частини об'єкта.

Приклад:

Я написав наступне в частині іншої відповіді на SO щодо цього:

POST:

Використовується для зміни та оновлення ресурсу

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Зауважте, що наступна помилка:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

Якщо URL ще не створено, ви   Не слід використовувати POST, щоб створити його   вказавши ім'я. Це має бути   призведе до помилки "ресурсу не знайдено"   оскільки <new_question> не існує   все-таки Ви повинні БУТИ <new_question>   спочатку ресурс на сервері.

Можна хоч би щось подібне   це для створення ресурсів з використанням POST:

POST /questions HTTP/1.1
Host: www.example.com/

Зазначимо, що в цьому випадку ресурс   Ім'я не вказано, нові об'єкти   URL шлях буде повернуто вам.

ВІДПРАВИТИ: 

Використовується для створення ресурсу, або   перезаписати його. Поки ви вкажете   Ресурси Нова URL-адреса.

Для нового ресурсу:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

Перезаписати існуючий ресурс:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

3487
2018-03-10 14:29



Я думаю, що недостатньо підкреслити той факт, що PUT є ідемпотентом: якщо мережа недоступна, а клієнт не впевнений, чи просив його прохання, він може просто надіслати його другий (або 100-й) час, і це гарантовано Специфікація HTTP, яка має точно такий же ефект, що й відправка одного разу. - Jörg W Mittag
@ Jörg W Mittag: Не потрібно. Другий час може повернути 409 Conflict або щось, якщо запит було змінено тимчасовим способом (деяким іншим користувачем або самим першим запитом, який пройшов). - Mitar
Якщо я не помиляюся, то, що ми повинні підкреслити, це ПУТЬ визначений бути ідемпотентом Ви все ще повинні писати свій сервер таким чином, щоб PUT поводився правильно, так? Можливо, краще сказати, що "PUT" призводить до того, що транспортне сполучення сприймає ідемопотенцію, що може вплинути на поведінку транспорту, наприклад, кешування ". - Ian Ni-Lewis
@ JörgWMittag Локальна фраза "Idempotency"? Як щодо "Відправити, відправляти і відправити мого друга, в кінці не має значення". - James Beninger
Думає про них як: PUT = вставити або оновити; POST = вставити. Отже, коли ви робите два PUT - ви отримуєте один новий запис, коли ви виконуєте два POSTs - ви отримуєте дві нові записи. - Eugen Konkov


Ви можете знайти твердження в Інтернеті, які говорять

І це не зовсім правильно.


Краще вибрати між PUT і POST на основі ідемопотуса дії

Випущений передбачає введення ресурсу - повністю замінивши все, що є на даній URL-адресі, інше. За визначенням, PUT є ідемпотентом. Робіть це стільки разів, скільки хочете, і результат однаковий. x=5 є ідемпотентом. Ви можете ВИПАДАТИ ресурс, незалежно від того, чи існував він раніше, чи ні (наприклад, для створення або оновлення)!

POST оновлює ресурс, додає дочірній ресурс або викликає зміни. POST не є ідемпотентним, таким чином, що x++ не ідемпотент


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

так:

POST /expense-report

або:

PUT  /expense-report/10929

1882
2018-04-22 14:55



Я погоджуюсь, де б не було ідемупотусі, воно повинно звузити будь-які інші турботи, оскільки помилки можуть призвести до багатьох несподіваних помилок. - Josh
Якщо POST може оновити ресурс, як це не ідемпотент? Якщо я змінюю вік учнів, використовуючи параметр PUT, і це в 10 разів перевищує вік студентів, якщо я це зробив один раз. - Schneider
@ Шнейдер, у цьому випадку ваш сервер докладає додаткових зусиль, щоб гарантувати ідемпотуси, але він не рекламує його. Веб-переглядачі все ж застерігають користувача, якщо вони намагаються перезавантажити такий запит POST. - Tobu
@Schneider POST може створити допоміжний ресурс; отже, ви можете постити до колекції, як POST / витрати-звіти і він створить стільки об'єктів (звітів про витрати) на вашому сервері, скільки кількість запитів, які ви надіслали, навіть якщо вони повністю схожі. Подумайте про це, як вставити той самий рядок у таблицю БД (/ reports-витрати) з автоматичним збільшенням первинного ключа. Дані залишаються однаковими, ключ (URI у цьому випадку) генерується сервером і відрізняється для кожної іншої вставки (запит). Отже, POST ефект може бути ідемпотентом, але також може ні. Отже, POST є ні ідемпотент - Snifff
Скажімо, у нас є об'єкти, які можуть мати два властивості - name і date. Якщо у нас є сутність з існуючим name і date, але потім внесіть запити до нього, вказавши лише a name, належна поведінка Випущений було б знищити date в той час як POST може оновити лише зазначені властивості, залишаючи невизначені властивості, як вони були до того, як було зроблено запит. Чи це звучить правильно / розумно, чи це неналежне використання Випущений (Я бачив посилання на ПАТЧ, що, здається, буде більш доречним, але ще не існує)? - Jon z


  • POST до URL-адреси створює дитячий ресурс в а Сервер визначений URL-адреса
  • Випущений до URL-адреси створює / замінює ресурс в цілому на клієнт визначений URL-адреса
  • ПАТЧ до URL-адреси оновлення частина ресурсу на вказаному клієнту URL-адресу.

Відповідна специфікація для PUT та POST - це RFC 2616 §9.5фф.

POST створює дочірній ресурс, так POST до /items створює ресурси, які живуть під /items ресурс Напр. /items/1. Відправка одного і того ж поштового пакунка двічі створює два ресурси.

Випущений є для створення або заміни ресурсу на URL, відомий клієнту.

Тому: Випущений є лише кандидатом на CREATE, де клієнт вже знає URL-адресу, перш ніж створюється ресурс. Напр. /blogs/nigel/entry/when_to_use_post_vs_put оскільки заголовок використовується як ключ ресурсу

Випущений замінює ресурс на відому URL-адресу, якщо він вже існує, тому відправка одного і того ж запиту двічі не має ефекту. Іншими словами, дзвінки на ПУТ є ідемпотентними.

RFC читається так:

Фундаментальна різниця між запитами POST і PUT відображається в різному значенні Request-URI. URI в запиті POST ідентифікує ресурс, який буде обробляти доданий об'єкт. Цей ресурс може бути процесом прийняття даних, шлюзом до іншого протоколу або окремого об'єкта, який приймає анотації. На відміну від цього, URI в запиті PUT ідентифікує об'єкт, що міститься в запиті, - користувальницький агент знає, який URI призначений, і сервер НЕ повинен намагатися застосувати запит до якогось іншого ресурсу. Якщо сервер бажає, щоб запит було застосовано до іншого URI,

Примітка: PUT в основному використовується для оновлення ресурсів (шляхом заміни їх у повному обсязі), але останнім часом відбувається рух до використання PATCH для оновлення існуючих ресурсів, оскільки PUT зазначає, що він замінює весь ресурс. RFC 5789.


563
2018-04-07 05:52



Або з іншої сторони паркану: PUT, якщо клієнт визначає адресу, що отримує ресурс, POST, якщо сервер це робить. - DanMan
Я думаю, що цю відповідь потрібно редагувати, щоб зробити це більш зрозумілим, що сказав @DanMan дуже простим способом. Найціннішим тут є примітка наприкінці, в якій зазначено, що PUT слід використовувати лише для заміни всього ресурсу. - Hermes
Патч не є реалістичним варіантом протягом принаймні декількох років, але я згоден з ідеологією. - crush
Я намагаюся зрозуміти, але використання PUT для створення щось має сенс лише тоді, коли клієнт точно знає, що ресурсу ще не існує, чи не так? Слідуючи прикладом блогу, скажімо, ви створили сотні повідомлень блогу через пару років, потім випадково вибираєте те саме назва, що і ви для публікації два роки тому. Тепер ви пішли і замінили цю посаду, яка не була призначена. Тож, використовуючи PUT для створення, клієнтові потрібно буде стежити за тим, що було зроблено, а що ні, і може призвести до нещасних випадків та непередбачених побічних ефектів, а також мати маршрути, які виконують дві абсолютно різні речі? - galaxyAbstractor
Ви праві. Вирішення публікації блогу з тим самим URL-адресою, що й існуюче, призведе до оновлення цього існуючого повідомлення (хоча ви, мабуть, могли б перевірити спочатку за допомогою GET). Це вказує, чому було б поганою ідеєю використовувати лише заголовок як URL-адресу. Однак це працюватиме там, де є природний ключ у даних ... що на мій досвід рідко. Або якщо ви використали ідентифікатори GUID - Nigel Thorne


Підсумок:

Створити:

Можна виконати як з PUT, так і POST, таким чином:

Випущений

Створює THE новий ресурс з newResourceId як ідентифікатор, під URI / resources URI або колекція.

PUT /resources/<newResourceId> HTTP/1.1 

POST

Створює А. новий ресурс під URI / resources URI, або колекція. Зазвичай ідентифікатор повертається сервером.

POST /resources HTTP/1.1

Оновлення:

Можна тільки виконати PUT таким чином:

Випущений

Оновлює ресурс за допомогою existingResourceId як ідентифікатор, під URI / resources URI або колекція.

PUT /resources/<existingResourceId> HTTP/1.1

Пояснення:

Коли ви маєте справу з REST та URI як загальним, у вас є загальний на залишилося і конкретний на правильно. The генерики зазвичай називають колекції і тим більше конкретний предмети можна назвати ресурс. Зауважте, що a ресурс може містити а колекція.

Приклади:

<- generic - specific ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

Коли ви використовуєте POST, ви є завжди посилаючись на a колекція, тому щоразу, коли ви скажете:

POST /users HTTP/1.1

ви надсилаєте нового користувача до користувачів  колекція.

Якщо ви зайдете і спробуйте щось на зразок цього:

POST /users/john HTTP/1.1

він буде працювати, але семантично ви говорите, що хочете додати ресурс до Джон  колекція під користувачів  колекція.

Коли ви використовуєте PUT, ви посилаєтеся на a ресурс або окремий елемент, можливо, всередині a колекція. Отже, коли ви скажете:

PUT /users/john HTTP/1.1

ви повідомляєте про оновлення сервера або створіть його, якщо його не існує Джон  ресурс під користувачів  колекція.

Spec:

Дозвольте мені виділити деякі важливі частини специфікації:

POST

The POST Метод використовується для запиту вихідного сервера приймати сутність, що вкладена в запит як новий підлеглий ресурсу, ідентифікованого Request-URI в запитній лінії

Звідси створює новий ресурс на колекція.

Випущений

The Випущений Метод запитує, що додається об'єкт зберігається за наданим Request-URI. Якщо Request-URI посилається на вже існуючий ресурс, що додається суб'єкт слід розглядати як модифікована версія того, хто проживає на сервері походження. Якщо запит-URI робить не вказують на наявний ресурс, і це URI здатний бути визначеним як новий ресурс Запитуючим користувацьким агентом, сервер походження може створити ресурс з цим URI ".

Отже, створіть або оновлюйте на основі існування ресурс.

Довідка:


164
2017-08-14 22:47



Цей пост був корисним для мене в розумінні того, що POST додає "щось" як дитину до даної колекції (URI), тоді як PUT явно визначає "щось" на даному місці URI. - kwah
Це найкраща відповідь, ось, я думаю: ніхто з цього "POST не може оновити ресурс" дурниці. Мені подобається ваша заява: "Оновлення можна виконувати лише з PUT". - Thomas
Ні, PUT не для оновлення чи створення. Це для заміни. Зауважте, що ви нічого не можете замінити щось на ефект створення. - thecoshman
@ 7hi4g0 PUT призначена для оновлення з повною заміною, іншими словами, вона замінює. Ви ніщо не замінюєте чим-небудь чи щось із щось зовсім новим. PUT не для внесення незначних змін (якщо у вас немає клієнта, що зробить цю незначну зміну і надасть нову версію, навіть те, що залишається тим самим). Для часткової модифікації PATCH є методом вибору. - thecoshman
@thecoshman Ви могли б, але не було б надто зрозуміло, що створення також охоплюється там. У цьому випадку краще бути явним. - 7hi4g0


Я хотів би додати свою "прагматичну" пораду. Використовуйте PUT, коли ви знаєте "ідентифікатор", за допомогою якого можна зберегти об'єкт, який ви зберігаєте. Використання PUT не буде працювати надто добре, якщо вам потрібно, скажімо, створений базою даних ідентифікатор, який буде повернуто для вас для майбутніх пошуків або оновлень.

Отже: для збереження існуючого користувача або того, де клієнт генерує ідентифікатор, і він перевірив, що ідентифікатор унікальний:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

В іншому випадку використовуйте POST, щоб спочатку створити об'єкт, і PUT, щоб оновити об'єкт:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

155
2018-01-15 19:59



Насправді це повинно бути POST /users. (Зауважте, що /users є множиною.) Це впливає на створення нового користувача і перетворення його у динамічний ресурс /users колекція - DavidRR
@DavidRR бути чесним, як керувати групами - це ще одне обговорення. GET /users має сенс, він читається так, як ви хочете, але мені було б добре GET /user/<id> або POST /user (з корисним навантаженням для нового нового користувача), оскільки він правильно читається, "get me users 5" є непарним, але "користувач 5" є більш природним. Хоча б я, напевно, все-таки впав би на плюралізацію, хоча :) - thecoshman


POST означає "створити новий", як у "Ось введення для створення користувача, створити його для мене".

PUT означає "вставити, замінити, якщо вже існує", як в "Ось дані для користувача 5".

Ви POST на example.com/users, оскільки ви ще не знаєте URL-адресу користувача, хочете, щоб сервер створив його.

Ви перейшли на example.com/users/id, оскільки хочете замінити / створити a конкретний користувач

ОГОЛОШЕННЯ два рази з тими ж даними означає створення двох ідентичних користувачів з різними ідентифікаторами. ПОВИНЕН у два рази з тими самими даними створює користувача першим і оновлює його до того ж стану вдруге (без змін). Оскільки ви в кінцевому підсумку з таким же станом після PUT незалежно від того, скільки разів ви виконуєте його, він вважається "однаково потужним" кожен раз - ідемпотент. Це корисно для автоматичного повторного надсилання запитів. Більше не "ви впевнені, що бажаєте повторно надіслати", коли ви натискаєте кнопку "Назад" у браузері.

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


144
2017-10-23 14:27



Схильність може викликати те, що зазвичай його вчать, що вам потрібні лише два дієслова: GET and POST. GET, щоб отримати, POST змінити. Навіть PUT і DELETE виконувалися за допомогою POST. Запитуючи, що PUT дійсно означає 25 років пізніше, можливо, знаком, ми спочатку дізналися про це неправильно. Популярність REST привела людей до основ, де ми повинні тепер вивчити минулі помилкові помилки. POST було недооцінено, і зараз його часто навчають неправильно. Найкраща частина: "ПОСИЛАННЯ двічі за однакових даних означає створення двох однакових [ресурсів]". Чудова точка! - maxpolk
Як ви можете використовувати PUT для створення запису за ідентифікатором, як у вашому прикладі user 5 якщо цього ще не існує? Ви не маєте на увазі update, replace if already exists? або щось - Luke
@ Coulton: Я мав на увазі те, що я написав. Ви вставляєте користувач 5, якщо ви ЗНАЙТИ / users / 5 і # 5 ще не існує. - Alexander Torstling
@ Коултон: І PUT також може бути використаний для замінити значення а існуючий ресурс у всій його повноті. - DavidRR
"Вважати виклик через POST" ... турбота про те, щоб це обгрунтувати? - thecoshman


Використовуйте POST, щоб створити, і PUT, щоб оновити. Ось так робить Ruby on Rails, у всякому разі.

PUT    /items/1      #=> update
POST   /items        #=> create

104
2018-03-10 14:28



POST /items додає новий елемент до вже визначеного ресурсу ("item"). Це не означає, що, як відповідає відповідь, "створіть групу". Я не розумію, чому це має 12 голосів. - David J.
З коробки Rails не підтримує "створення групи" через REST. Щоб "створити групу", якою я маю на увазі "створити ресурс", ви повинні зробити це за допомогою вихідного коду. - David J.
Це справедливе керівництво, але надмірне спрощення. Як зазначають інші відповіді, цей метод може бути використаний як для створення, так і для оновлення. - Brad Koch
Я згоден з відповіддю з невеликою зміною. Використовуйте POST, щоб створити і ПУТЬ, щоб повністю оновити ресурс. Для часткових оновлень ми можемо використовувати PUT або PATCH. Скажемо, що ми хочемо оновити статус групи. Ми можемо використовувати PUT / groups / 1 / status з статусом - корисним навантаженням запиту або PATCH / groups / 1 з деталями про дію в корисному навантаженні - java_geek
Також слід чітко зрозуміти це PUT /items/42 також дійсний для створення ресурс але тільки в тому випадку, якщо клієнт має право присвоїти ресурс. (Чи дозволяє Rails надавати клієнту цю прізвиську присвоєння імен?) - DavidRR


REST - це а дуже концепція високого рівня. Фактично, HTTP взагалі навіть не згадується!

Якщо у вас є сумніви щодо того, як реалізувати REST в HTTP, ви завжди можете подивитися на Протокол публікації Atom (AtomPub) специфікація AtomPub - це стандарт для написання RESTful webservices з HTTP, який був розроблений багатьма HTTP і REST світилами, з деякими вченими Роя Філдінга, винахідника REST та (спів) винахідника самого HTTP.

Насправді, ви навіть зможете використовувати AtomPub безпосередньо. Хоча це вийшло з спільноти для ведення блогу, це ніяк не обмежується веденням блогу: це загальний протокол для взаємодії RESTfully з довільними (вкладеними) колекціями довільних ресурсів через HTTP. Якщо ви можете представляти вашу програму як вкладений набір ресурсів, ви можете просто використовувати AtomPub і не турбуватися про те, чи використовувати PUT або POST, які HTTP-коди статусу повернути, і всі ці дані.

Ось що говорить AtomPub про створення ресурсів (розділ 9.2):

Щоб додати учасників до колекції, клієнти надсилають запити POST на URI колекції.


57
2018-03-10 15:27



Немає нічого поганого, дозволяючи створювати ресурси. Просто пам'ятайте, що це означає, що клієнт надає URL-адресу. - Julian Reschke
Існує щось дуже неправильне, що дозволяє PUT створювати ресурси: клієнт надає URL-адресу. Це робота сервера! - Joshcodes
@Joshcodes Це не завжди так, що робота сервера - створити ідентифікатори клієнта. Я все частіше бачив конструкції, які дозволяють клієнтам створити якийсь UUID як ідентифікатор ресурсу. Ця конструкція, зокрема, дозволяє збільшити масштаб. - Justin Ohms
@JustinOhms Я згоден з вашою думкою про ідентифікатори, створені клієнтом (примітка: всі системи, розроблені мною з кінця 2008 року, вимагають від клієнта створити ідентифікатор як UUID / Guid). Це не означає, що клієнт повинен вказати URL-адресу. - Joshcodes
@Joshcodes Це питання розподілу проблем. Там, де генерується URL-адреса, насправді мало наслідків. Так, сервер несе відповідальність за доставку вмісту з правильної URL-адреси, але це не обмежує сервер від відповіді на запит з неправильною URL-адресою. Правильна відповідь з сервера у цьому випадку становить 308. Належний клієнт повторить спробу PUT на правильній URL-адресі. Інший приклад - це розподілена система, де не всі вузли знають про всі ресурси, надані клієнтами. Тут PUT для створення буде цілком правильним, оскільки для цього вузла сервера ресурсу не існує. - Justin Ohms


Рішення про те, чи використовувати PUT або POST для створення ресурсу на сервері за допомогою HTTP + REST API, залежить від того, хто володіє структурою URL-адреси. Якщо клієнт знає або бере участь у визначенні, структура URL-адреси є непотрібною сполукою, схожою на небажані зв'язки, що виникла з SOA. Зникаючі типи зчеплення - це причина, що РЕСТ настільки популярний. Тому правильним способом використання є POST. Існують винятки з цього правила, і вони виникають, коли клієнт хоче зберегти контроль над структурою розташування ресурсів, які він використовує. Це рідко, ймовірно, означає, що щось інше не так.

На цьому етапі деякі люди стверджують, що якщо RESTful-URL-адреси використовуються, клієнт не знає URL-адресу ресурсу, і тому PUT є прийнятним. Зрештою, саме тому канонічні, нормалізовані, Ruby on Rails, URL-адреси Django є важливими, подивіться на Twitter API ... бла бла бла. Ці люди повинні розуміти немає такої речі, як Restful-URL і це Рої Філдінг стверджує це:

API REST не повинен визначати фіксовані імена ресурсів або ієрархії (an   Очевидне зчеплення клієнта і сервера). Сервери повинні мати свободу   контролювати власне простір імен. Замість цього дозвольте серверам навчати   клієнти про те, як побудувати відповідні URI, наприклад, виконано в HTML   форми та шаблони URI, визначаючи ці інструкції в медіафайлах   типи та зв'язки. [Невдача тут означає, що клієнти є   беручи до уваги структуру ресурсів через нестандартну інформацію, таку як   стандартний домен, який є еквівалентним для даних   Функціональна з'єднання RPC].

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

Ідея а RESTful-URL насправді є порушенням REST, оскільки сервер відповідає за структуру URL-адреси і повинен вільно вирішувати, як його використовувати, щоб уникнути з'єднання. Якщо це сплутати вас з тим, що ви читаєте про значення саморозкриття на дизайн API.

Використання POST для створення ресурсів поставляється з дизайнерським розглядом, оскільки POST не є ідемпотентним. Це означає, що повторити POST кілька разів не гарантує однакову поведінку кожного разу. Це заважає людям використовувати PUT для створення ресурсів, коли вони не повинні. Вони знають, що це неправильно (POST - це для CREATE), але вони роблять це в будь-якому випадку, тому що вони не знають, як вирішити цю проблему. Ця занепокоєння продемонстровано в такій ситуації:

  1. Клієнт POST - новий ресурс для сервера.
  2. Сервер обробляє запит і надсилає відповідь.
  3. Клієнт ніколи не отримує відповіді.
  4. Сервер не знає, що клієнт не отримав відповіді.
  5. Клієнт не має URL-адреси для ресурсу (тому PUT не є варіантом) і повторяє POST.
  6. POST не ідемпотент, а сервер ...

Крок 6 - це місце, де люди часто бентежать про те, що робити. Проте немає ніяких підстав створити таку проблему для вирішення цієї проблеми. Замість цього HTTP може використовуватися, як вказано в RFC 2616 і сервер відповідає:

10.4.10 409 Конфлікт

Запит не може бути завершений через конфлікт із поточним   стан ресурсу. Цей код дозволено лише в ситуаціях, коли   очікується, що користувач зможе вирішити конфлікт і   повторно надіслати запит. Відповідний орган ДОЛЖЕН включати достатньо

інформація, щоб користувач розпізнавав джерело конфлікту.   В ідеалі об'єкт відповіді повинен містити достатньо інформації для   користувач або агент користувача для вирішення проблеми; Однак це не може бути   можливо і не потрібно.

Найчастіше конфлікти можуть виникнути у відповідь на запит PUT. Для   Наприклад, якщо використовується версію, а особа, що є PUT   містять зміни до ресурсу, які суперечать тим, які зроблені a   раніше (сторонній) запит, сервер може використати відповідь 409   щоб вказати, що він не може виконати запит. У цьому випадку,   Реакція об'єкта, ймовірно, міститиме список відмінностей між   дві версії у форматі, визначеному відповіддю Content-Type.

Відповідь з кодом стану 409 Conflict є правильним регресом, оскільки:

  • Виконання POST даних, які мають ідентифікатор, який відповідає ресурсу, вже в системі, "є конфліктом з поточним станом ресурсу".
  • Оскільки важлива частина полягає в тому, щоб клієнт зрозумів, що сервер має ресурс, і вжити відповідних заходів. Це "ситуація (і), де очікується, що користувач зможе вирішити конфлікт і повторно надіслати запит".
  • Відповідь, яка містить URL-адресу ресурсу з конфліктуючим ідентифікатором та відповідні передумови для цього ресурсу, забезпечить "достатньо інформації для користувача чи агента користувача для вирішення проблеми", що є ідеальним випадком для RFC 2616.

Оновлення на основі випуску RFC 7231 для заміни 2616

RFC 7231 призначений для заміни 2616 і дюйма Розділ 4.3.3 описує наступну можливу відповідь для POST

Якщо результат обробки POST буде еквівалентний a   представлення існуючого ресурсу, сервер походження МОЖЕТ переадресовувати   агента користувача до цього ресурсу, відправивши відповідь 303 (Див. Інше)   з ідентифікатором існуючого ресурсу у полі Місцезнаходження. Це   має переваги надання користувачеві агента ідентифікатора ресурсу   і перенесення представлення за допомогою методу, який можна піддавати   Спільне кешування, хоча за рахунок додаткового запиту, якщо користувач   агент ще не має представлення кешування.

Тепер може бути спокусливо просто повернути 303 у випадку повторення POST. Проте, навпаки, це правда. Повернення 303 буде мати сенс лише тоді, коли кілька запитів на створення (створення різних ресурсів) повертають один і той же вміст. Прикладом може бути "дякую вам за подання вашого повідомлення про запрошення", що клієнтові не потрібно повторно завантажувати кожен раз. RFC 7231 як і раніше стверджує в розділі 4.2.2, що POST не є ідемпотентним і продовжує стверджувати, що POST слід використовувати для створення.

Щоб отримати додаткову інформацію про це, прочитайте це стаття.


53
2017-10-29 23:00



Чи буде відповідь 409 Conflict відповідним кодом для щось на кшталт спроби створення нового облікового запису з ім'ям, яке вже існує? Я спеціально використовував 409 для конфліктів версій, але після прочитання вашої відповіді я задаюсь питанням, чи не слід використовувати його для будь-яких "дубльованих" запитів. - Eric B.
@ EricB Так, у ситуації, яку ви називаєте "через конфлікт із поточним станом ресурсу", операція не виконується. Крім того, розумно очікувати, що користувач може вирішити конфлікт, і орган повідомлення повинен лише інформувати користувача про те, що ім'я користувача вже існує. - Joshcodes
@Joshcodes ви можете сказати більше про процес вирішення конфлікту? У такому випадку, якщо ім'я користувача вже існує, клієнт повинен підказати кінцевому користувачеві інше ім'я користувача? Що робити, якщо клієнт намагається використовувати POST для зміни імені користувача? Чи повинні PUT-запити все-таки бути використані для оновлення параметрів, тоді як POST використовується для створення об'єктів, будь то один за раз чи декілька? Дякую. - BFar
@ BFar2, якщо ім'я користувача вже існує, тоді клієнт повинен запросити користувача. Щоб змінити ім'я користувача, припускаючи, що ім'я користувача є частиною вже створеного ресурсу, який потребує модифікації, PUT буде використовуватися, оскільки ви правильні, POST використовується для створення, завжди і ПУТЬ для оновлень. - Joshcodes
Визначення речей, використовуючи коротку та ефективну мову, також є бажаною майстерністю - Junchen Liu


Мені подобається ця порада, від RFC 2616 - визначення PUT:

Фундаментальна різниця між запитами POST і PUT відображається в різному значенні Request-URI. URI в запиті POST ідентифікує ресурс, який буде обробляти доданий об'єкт. Цей ресурс може бути процесом прийняття даних, шлюзом до іншого протоколу або окремого об'єкта, який приймає анотації. На відміну від цього, URI в запиті PUT ідентифікує об'єкт, що міститься в запиті, - користувальницький агент знає, який URI призначений, і сервер НЕ повинен намагатися застосувати запит до якогось іншого ресурсу.

Подібно до інших порад тут, що PUT найкраще застосовується до ресурсів, які вже мають ім'я, і ​​POST це добре для створення нового об'єкта під існуючим ресурсом (і давши назву серверу).

Я це інтерпретую, і вимоги ідемпотентності щодо ПУТ, це означає, що:

  • POST підходить для створення нових об'єктів під колекцією (і створення не повинно бути ідемпотентним)
  • PUT добре для оновлення існуючих об'єктів (і оновлення має бути ідемпотентним)
  • POST також може використовуватися для не-ідемпотентних оновлень існуючих об'єктів (особливо, змінюючи частину об'єкта, не вказуючи все це - якщо ви думаєте про це, створення нового члена колекції насправді є особливим випадком такого роду оновлення з точки зору колекції)
  • PUT також може бути використаний для створення, якщо і тільки якщо дозволити клієнту називати ресурс. Але оскільки клієнти REST не повинні робити припущення щодо структури URL-адреси, це менше в задуманому дусі речей.

48
2018-01-11 17:18



"POST також може бути використаний для не-ідемпотентних оновлень існуючих об'єктів (особливо, змінюючи частину об'єкта, не вказуючи всю річ" Ось що PATCH для - Snuggs