Який правильний код відповіді REST для дійсного запиту, але порожні дані?


331

Наприклад, ви запускаєте GET-запит, users/9але немає користувача з ідентифікатором №9. Який найкращий код відповіді?

  • 200 ОК
  • 202 Прийнято
  • 204 Немає вмісту
  • 400 Поганий запит
  • 404 Не знайдено

19
Підказка: Ви знайшли користувача 9?
Кріс Пфол

42
Підказка 2: Отже, користувача 9 не знайдено ?
Томаш Нуркевич

18
@IMB хто говорить 204? "Без вмісту" вказує, що потрібна організація існує, але не має представництва. Наприклад, якщо в блозі з id 15 немає коментарів, і ви не хочете повертати порожній список для коментарів блогу № 15: "/ blog / 15 / comments" поверне NoContent. З іншого боку, якщо блог 15 існує, "404 не знайдено" є більш підходящим.
Кріс Пфол

12
@Crisfole ти не мав на увазі ". З іншого боку, якщо блогу 15 не існує," 404 Not Found "є більш підходящим"
gdoron підтримує Моніку

15
Я, безумовно, зробив @gdoron! :) Дякую. На жаль, я приблизно на три роки запізнився, щоб відредагувати це та виправити.
Кріс Пфол

Відповіді:


249

TL; DR: Використання 404

Дивіться цей блог . Це дуже добре пояснює.

Короткий зміст коментарів блогу щодо 204:

  1. 204 No Content не дуже корисно як код відповіді для веб-переглядача (хоча, згідно з специфікаціями HTTP, браузерам потрібно розуміти це як код відповіді "не змінювати погляд").
  2. 204 No Content це , однак, дуже корисно для AJAX веб - сервісів , які можуть хотіти , щоб вказати успіх без необхідності щось то повернути. (Особливо в таких випадках , як DELETEі POSTз , які не вимагають зворотного зв'язку).

Отже, відповідь на ваше запитання - це використання 404у вашому випадку. 204це спеціалізований код відгуку, який не слід часто повертати до браузера у відповідь на GET.

Інші коди відповідей, які ще менш підходящі , ніж 204та 404:

  1. 200слід повернути разом з тілом все, що ви успішно дістали. Недоцільно, коли сутність, яку ви отримуєте, не існує.
  2. 202використовується, коли сервер розпочав роботу над об'єктом, але об'єкт ще не повністю готовий. Звичайно, це не так. Ви не розпочали і не почнете конструювання користувача 9 у відповідь на GETзапит. Це порушує всілякі правила.
  3. 400використовується у відповідь на погано відформатований запит HTTP (наприклад, неправильно сформовані заголовки http, неправильно упорядковані сегменти тощо). З цим майже напевно впорається будь-яка рамка, яку ви використовуєте. Вам не доведеться з цим боротися, якщо ви не пишете власний сервер з нуля. Редагувати : новіші RFC тепер дозволяють використовувати 400 для семантично недійсних запитів.

Опис Вікіпедії щодо кодів статусу HTTP особливо корисний. Ви також можете побачити визначення в документі HTTP / 1.1 RFC2616 на веб-сайті www.w3.org


8
Примітка: коди відповідей у ​​200-х роках свідчать про успіх. Коди відповідей у ​​400-х роках вказують на збій. Підсумок, пункти перша і друга, стосується 204коду відповіді (Без вмісту).
Кріс Пфол

227
-1 тому що я занадто рішуче проти 404 як відповідь на успішний дзвінок, який не має записів для повернення. Як розробник, що займається API для не-веб-додатків, я витрачав години на зв’язок із розробниками API, щоб з’ясувати, чому кінцева точка API, яку я викликав, не існувала, а насправді це було, просто не було дані для звіту. Що стосується 204, який не є особливо корисним для браузера, це трохи схоже на хвіст, що витає собаку, оскільки більшість застосувань кінцевих точок API у нашому Всесвіті розумних пристроїв не базується на веб-переглядачах і тих, які, ймовірно, використовують AJAX. Вибачте, що забрали очки, хоча.
Метт Кашатт

38
@MatthewPatrickCashatt Ви можете вільно відмовитись, як завгодно. Зараз я нарешті розумію, чому люди піддаються мені, але обґрунтування все ще неправильне. Отримавши номер 404, це не означає, що маршрут не має сенсу, це означає, що в цьому місці немає ресурсу. Повна зупинка. Це справедливо, якщо ви звертаєтесь із запитом /badurlабо /user/9коли такого користувача не існує. Розробник може допомогти, додавши кращу причину фрази, ніж "Не знайдено", але цього не потрібно.
Кріс Пфол

19
@Crisfole Я схильний не погоджуватися (хоч і не зволікаю, але читайте), виходячи конкретно з визначення W3 404 , зокрема The server has not found anything matching the Request-URI. Насправді сервер веб-додатків знайшов дію, що відповідає запиту URI, хоча сервер db цього не зробив. Однак він також говорить This status code is commonly used when [...] no other response is applicable, тому я думаю, що це дещо підтверджує його використання (навіть якщо я не згоден з / подобається).
Девін

8
Я не думаю, що ви звертаєтесь до питання, яке я зазначаю: 404 небезпечно заплутано. Покладаючись на те, що абонент перевіряє фразу причини або тіло відповіді, означає, що ви не довіряєте коду статусу, і в цьому випадку це не корисно.
Адріан Бейкер

364

Я категорично проти 404 на користь 204 або 200 із порожніми даними. Або хоча б слід використовувати об'єкт відповіді з 404.

Запит був отриманий та оброблений належним чином - він запустив код програми на сервері, тому реально не можна сказати, що це клієнтська помилка, і тому весь клас кодів помилок клієнта (4xx) не відповідає.

Що ще важливіше, 404 може статися з ряду технічних причин. Наприклад, програма тимчасово деактивована або видалена на сервері, проблеми з підключенням проксі та інше. Тому клієнт не може розрізняти 404, що означає "порожній набір результатів", і 404, що означає "службу неможливо знайти, спробуйте пізніше".

Це може бути фатальним: Уявіть собі бухгалтерську службу у вашій компанії, яка перераховує всіх працівників, яким виплачується щорічна премія. На жаль, щоразу, коли він називається, він повертає 404. Чи означає це, що ніхто не повинен платити за бонус, або що додаток наразі не працює для нового розгортання?

-> Для прикладних програм, які піклуються про якість своїх даних, 404 без об'єкта відповідей, таким чином, майже не займається.

Крім того, багато клієнтських систем відповідають на 404, кидаючи виняток, не задаючи більше запитань. Це змушує розробника клієнта зловити цей виняток, оцінити його, а потім вирішити, виходячи з цього, чи слід фіксувати його як помилку, яку вибирає, наприклад, компонент моніторингу, чи слід ігнорувати його. Мені це теж не здається гарним.

Перевага 404 перед 204 полягає в тому, що він може повернути об'єкт відповіді, який може містити певну інформацію про те, чому запитуваний ресурс не знайдено. Але якщо це дійсно актуально, то можна також розглянути можливість використання відповіді 200 ОК та спроектувати систему таким чином, що дозволяє реагувати на помилки у даних корисного навантаження. Крім того, можна використовувати корисне навантаження відповіді 404 для повернення структурованої інформації абоненту. Якщо він отримує, наприклад, сторінку html замість XML або JSON, що він може розібратися, то це хороший показник того, що щось технічне пішло не так замість відповіді "без результату", що може бути дійсним з точки зору абонента. Або можна використовувати для цього заголовок відповіді HTTP.

Все-таки я вважаю за краще 204 або 200 з порожньою відповіддю, хоча. Таким чином статус технічного виконання запиту відокремлюється від логічного результату запиту. 2xx означає "технічне виконання нормально, це результат, вирішуйте це".

Я думаю, що в більшості випадків клієнт повинен залишати рішення про те, допустимий чи ні порожній результат. Повертаючи 404 без відповіді, незважаючи на правильне технічне виконання, клієнт може вирішити вважати випадки помилками, які просто не мають помилок.

Ще одна швидка аналогія: Повернення 404 для "не знайдено результату" - це як викидання DatabaseConnectionException, якщо запит SQL не повернув результатів. Це може виконати роботу, але існує маса можливих технічних причин, які викидають той самий виняток, який потім був би помилково прийнятий за дійсний результат.


30
Технічні причини "не знайдено" також відомі як помилки сервера. Це повинно бути в 500-х. Конкретно: "Службу неможливо знайти" є 503 Service Unavailable.
Кріс Пфол

43
Автор запитував також про конкретний ресурс: одного користувача (не /usersмаршрут, але /users/9, наприклад, "Користувач, відомий як # 9"), тому порівняння "порожнього набору результатів" не має сенсу. 404 означає, що об'єкт не існує.
Кріс Пфол

29
404 просто вказує, що запитуваний ресурс (у даному випадку номер 9) не знайдено. Це не має нічого спільного з тим, чи був знятий код програми чи ні, він не має нічого спільного з тим, відповів чи ні бекенд-додаток. Веб-сервер - це те, про що йшлося, не було згадки про зворотне наближення до запитання.
Кріс Пфол

29
Міркування у цій відповіді жахливо помилкові.
Курт Шпіндлер

20
404: клієнт зміг спілкуватися з даним сервером, але сервер не міг знайти те, що було запитувано. Буквально це: запит отриманий, він був точним і належним чином відформатований (неправильний запит 400), він був засвідчений автентичністю або відкритим (несанкціонований 401 / заборонений 403), платіж не потрібен (платіж потрібен 402), спосіб запиту був нормальним (метод заборонений 405 ), прийняття запиту може бути задоволено (не прийнятно 406). 200 Ок слід використовувати, коли користувач отримує ресурс. Порожня - це не ресурс. 400 діапазон для помилок клієнта 500 діапазон - для помилок сервера Коротше: Ваші міркування вимкнено.
Дерк-Січ

62

Спочатку я думав, що 204 має сенс, але після обговорень я вважаю, що 404 є єдиною вірною правильною відповіддю. Розглянемо наступні дані:

Користувачі: Джон, Пітер

METHOD  URL                      STATUS  RESPONSE
GET     /users                   200     [John, Peter]
GET     /users/john              200     John
GET     /users/kyle              404     Not found
GET     /users?name=kyle`        200     []
DELETE  /users/john              204     No Content

Деякі відомості:

  1. пошук повертає масив, у нього просто не було збігів, але він містить вміст: порожній масив .

  2. 404, звичайно, найвідоміший за URL-адресами, які не підтримуються запитуваним сервером, але відсутній ресурс насправді той самий.
    Незважаючи на те, /users/:nameзіставляється з users/kyle, користувач Кайл не доступний ресурс тому 404 все ще застосовується. Це не пошуковий запит, це пряма посилання динамічним URL-адресом , тому 404 це.

У всякому разі, мої два центи :)


9
Кидаючи свою вагу на цей стиль для API REST. Жоден клієнт не повинен просити / користувачів / кайла, якщо йому не сказали, що ресурс існуватиме через дзвінок або / користувачам, або / користувачам? Name = kyle
Gary Barker

@GaryBarker Але оскільки це "введення користувача" в якийсь спосіб, API все-таки повинен правильно поводитися. Хоча ви повинні запобігти 404 у вашому клієнті, ви не можете бути впевнені, що він насправді був перевірений. Проектування API слід здійснювати без врахування точної реалізації вашого клієнта, особливо з точки зору перевірених даних користувачів.
RicoBrassers

Це відповідь, з якою я найбільше згоден. Ідеальний приклад того, як я хочу працювати API. @ Коментар GaryBarker теж ідеальний. Це помилка, коли ви шукаєте щось за ідентифікатором, а воно не існує. Ви повинні знати, що ідентифікатор існує перед тим, як телефонувати. Переважно тому, що отримання деякої "успішної" порожньої відповіді просто натискає на помилку далі по дорозі, ймовірно, хтось із "не може прочитати ім'я властивості невизначеного", роблячи user.name або щось подібне.
Джеймі Твіллс

Як щодо комбінації двох. Якщо припустити, що у користувачів є друзі. / користувачів / kyle / друзів? name = fred. Кайла не існує, тож ця відповідь була б 404? Або це було б 200, тому що ми не дуже піклуємось про Кайла, ми дбаємо лише про пошук його друзів з ім'ям Фред?
JSextonn

ІМО, який би дав 404, оскільки це недійсний запит: Кайл не існує, тому пошук його друзів також неможливий.
Юстус

23

Якщо очікується, що ресурс існує, але він може бути порожнім, я б стверджував, що може бути простіше просто отримати 200 ОК з поданням, яке вказує на те, що річ порожня.

Тож я вважаю за краще / речі повертають 200 ОК із {"items": []}, ніж 204 без нічого, тому що таким чином колекція з 0 предметами може трактуватися так само, як колекція з одним або більше предмета в ньому.

Я просто лишаю 204 Без вмісту для PUT та DELETE, де, можливо, справді немає корисного представлення.

У випадку, якщо / thing / 9 насправді не існує, 404 підходить.


1
Це здається, що ви віддаєте перевагу програмувати проти API, використовуючи більш абстраговану форму під назвою RPC. Замість того, щоб отримувати доступ до ресурсів, дотримуючись уважно дієслів та URL-адресу, засновану на ресурсах, наприклад customers/1/addressbook, RPC спосіб полягає в тому, щоб викликати кінцеву точку на зразок GetCustomerAddressBookі отримувати дані або по суті нульові, і не потрібно так сильно турбуватися про складності HTTP. У обох є плюси і мінуси.
Людина-булочка

2
@ Чоловік Muffin, я не впевнений, як можна зробити вигляд, що я вважаю, що я віддаю перевагу REST або RPC, а також чому це стосується дискусії про те, який код статусу повернутись до HTTP GET-запиту.
j0057

У мене виникли жахливі проблеми кешування під час використання 204. Chrome ставиться до запиту дивно, і нічого не відображатиметься в мережі та кешує попередній результат. Навіть із усіма заголовками без кешу у світі. Я згоден з цією відповіддю, 200 видається найкращим із порожнім масивом / об’єктом, переданим користувачеві.
Джек

22

У попередніх проектах я використовував 404. Якщо немає користувача 9, об'єкт не знайдено. Тому 404 Не знайдено є відповідним.

Оскільки об’єкт існує, але даних немає, 204 Немає відповідного вмісту. Я думаю, що у вашому випадку об’єкта не існує.


14

Згідно з публікацією w3 ,

200 ОК

Запит вдався. Інформація, що повертається з відповіддю, залежить від методу, який використовується у запиті

202 Прийнято

Запит прийнято для обробки, але обробка не завершена.

204 Немає вмісту

Сервер виконав цей запит, але йому не потрібно повертати сутність, і може захотіти повернути оновлену інформацію.

400 Поганий запит

Сервер не міг зрозуміти запит через неправильний синтаксис. Клієнт НЕ повинен повторювати запит без змін

401 Несанкціонований

У запиті потрібна автентифікація користувача. Відповідь ОБОВ'ЯЗКОВО включає поле заголовка WWW-Authenticate

404 Не знайдено

Сервер не знайшов нічого, що відповідає Request-URI. Не вказується, чи є стан тимчасовим чи постійним


У публікації w3 йдеться про коди статусу HTTP. HTTP не ідентичний REST. REST в основному, але не обов'язково використовує HTTP як транспортний протокол. 404 - код помилки транспорту HTTP. Якщо REST був би таким же, як HTTP, чи не повинен він називатися HTTP?
анеб

1
@anneb Як ви сказали, REST використовує HTTP, тому ця відповідь цілком має сенс. REST - це не HTTP, REST не є протоколом. REST не повинен бути ідентичним (або таким же, як HTTP), щоб ця відповідь не мала сенсу.
Корай Тугай

@Koray Tugay: пошук у Google також використовує http, тому відповідно до цієї відповіді пошук Google повинен відповідати статусу 404 http, якщо нічого не відповідає пошуку?
анеб

@anneb Чи є в пошуку Google ви згадуєте програму RESTful? Я так не думаю .. Отже, відповідь буде "ні". Повернувшись до оригінального запитання, і ця відповідь замість того, щоб потрапити в кролячу нору. Якщо Пошук Google одного дня створить API RESTful (або, можливо, він уже є, я не знаю), він може повернутися, 204 No Contentколи не знайде результатів. Ні 404, це результат для вас, але він не має змісту ..
Корай Тугай

13

Щоб узагальнити або спростити,

2xx: Необов'язкові дані: Добре сформований URI: Критерії не є частиною URI: Якщо критерії необов’язкові, які можна вказати в @RequestBody та @RequestParam, це повинно призвести до 2xx. Приклад: фільтр за назвою / статусом

4xx: Очікувані дані: Недостатньо сформований URI: Критерії є частиною URI: Якщо критерії є обов'язковими, їх можна вказати лише в @PathVariable, то це повинно призвести до 4xx. Приклад: пошук за унікальним ідентифікатором.

Таким чином, для запитуваної ситуації: "користувачів / 9" буде 4xx (можливо, 404) Але для "користувачів? Ім'я = супермен" має бути 2xx (можливо, 204)


12

Поставлено два запитання. Один у назві та один у прикладі. Я думаю, що це частково призвело до суперечки щодо того, яка відповідь є підходящою.

Назва запитання задає порожні дані. Порожні дані все ще є даними, але не є такими ж, як відсутні дані. Отже, це пропонує запитувати набір результатів, тобто список, можливо, від /users. Якщо список порожній, він все ще залишається, тому 204 (Без вмісту) є найбільш підходящим. Ви тільки що попросили список користувачів і його отримали, він просто не має вмісту.

Наведений приклад запитує про конкретний об'єкт, користувача /users/9,. Якщо користувача №9 не знайдено, жоден об’єкт користувача не повертається. Ви запитували певний ресурс (об’єкт користувача) і не давали йому, оскільки його не було знайдено, тому 404 є відповідним.

Я думаю, що спосіб вирішити це, якщо ви можете використовувати відповідь так, як ви очікували, не додаючи жодного умовного твердження, тоді використовуйте 204, інакше використовуйте 404.

У моїх прикладах я можу переглядати порожній список, не перевіряючи, чи є у нього вміст, але я не можу відображати дані об’єкта користувача на об’єкті, що не має значення, нічого не порушуючи або додаючи чек, щоб побачити, чи він є нульовим.

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


9

Оглянувши питання, ви не повинні використовувати 404чому?

На основі RFC 7231 правильний код статусу204

У пришельниках вище я помітив 1 невелике непорозуміння:

1.- ресурс: /users

2.- /users/8це не ресурс, це: ресурс /usersз параметром маршруту 8, споживач, можливо, не може його помітити і не знає різниці, але видавець це і повинен знати! ... тому він повинен повернути точну відповідь для споживачів. періоду.

тому:

На основі RFC: 404 невірно, оскільки /usersзнайдені ресурси , але логіка, виконана за допомогою параметра 8, не знайшла жодного contentповернення як відповідь, тому правильна відповідь:204

Тут головне: 404навіть не знайдено ресурсу для обробки внутрішньої логіки

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

200: нормально, я знайшов ресурс, логіка була виконана (навіть коли я нічого не змушений повертати), взяти це і використовувати його за своїм бажанням.

205: (найкращий варіант відповіді GET) Я знайшов ресурс, виконувалась логіка, у мене є для вас якийсь вміст, добре використовуйте його, о, до речі, якщо ви збираєтеся поділитися цим у поданні, будь ласка, оновіть перегляд на відобразити його.

Сподіваюся, це допомагає.


8

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

  • У випадку параметрів шляху параметр є частиною шляху до ресурсу. У випадку /users/9відповіді має бути, 404оскільки цей ресурс не знайдено. /users/9- це ресурс, а результат - одинаковий, або помилка, його не існує. Це не монада.
  • У випадку параметрів запиту параметр не є частиною шляху до ресурсу. У випадку /users?id=9, відповідь повинна бути, 204оскільки ресурс /usersбув знайдений, але він не міг повернути жодних даних. Ресурс /usersіснує і результат n-ary, він існує, навіть якщо він порожній. Якщо idунікальний, це є монадой.

Використовувати параметри шляху або параметри запиту, залежить від випадку використання. Я віддаю перевагу параметрам шляху для обов'язкових, нормативних або ідентифікаційних аргументів та параметрів запиту для необов'язкових, ненормативних або присвоюючих аргументів (наприклад, підказка, локалізація зіставлення та інше). У API REST я використовував би /users/9не /users?id=9особливо через можливе введення, щоб отримати "дочірні записи", як, наприклад, /users/9/ssh-keys/0отримати перший відкритий ключ ssh або /users/9/address/2отримати третю поштову адресу.

Я вважаю за краще використовувати 404. Ось чому:

  • Заклики до одинарного (1 результат) та n-арного (n результатів) методів не повинні змінюватися без поважних причин. Мені подобається мати однакові коди відповідей, якщо це можливо. Кількість очікуваних результатів, звичайно, є різницею, скажімо, ви очікуєте, що тіло буде об'єктом (одинарним) або масивом об'єктів (n-ary).
  • Для n-ary я б повернув масив, і якщо результатів не буде, я б не повернув жодного набору (жодного документа), я б повернув порожній набір (порожній документ, як порожній масив у JSON або порожній елемент у XML ). Тобто, це ще 200, але з нульовими записами. Немає підстав розміщувати цю інформацію на дроті, окрім корпусу.
  • 204це як voidметод. Я б не використати його для GET, тільки POST, PUTі DELETE. Я роблю виняток у випадку, GETколи ідентифікатори - це параметри запиту, а не параметри шляху.
  • Не знайшовши записи, як NoSuchElementException, ArrayIndexOutOfBoundsExceptionабо що - щось подібне, викликане клієнтом, ідентифікатор , який не існує, тому, це помилка клієнта.
  • З точки зору коду, отримання 204означає додаткову гілку в коді, якої можна було б уникнути. Це ускладнює клієнтський код, а в деяких випадках також ускладнює код сервера (залежно від того, чи використовуєте ви сутність / модель монади чи звичайні сутності / моделі; і я настійно рекомендую триматися подалі від монад суті / моделі, це може призвести до неприємних помилок де монади ви вважаєте, що операція успішна, і поверніть 200 або 204, коли ви насправді повинні повернути щось інше).
  • Клієнтський код простіше написати і зрозуміти, якщо 2xx означає, що сервер зробив те, що просив клієнт, а 4xx означає, що сервер не робив те, що вимагав клієнт, і це вина клієнта. Якщо клієнт не записує, що клієнт запитував ідентифікатор, це помилка клієнта, оскільки клієнт запитав ідентифікатор, який не існує.

І останнє, але не менш важливе: послідовність

  • GET /users/9
  • PUT /users/9 і DELETE /users/9

PUT /users/9і DELETE /users/9вже доведеться повернутись 204у разі успішного оновлення чи видалення. То що їм повернути, якщо користувач 9 не існував? Немає сенсу мати ту саму ситуацію, що і різні коди статусу залежно від використовуваного методу HTTP.

Крім того, не нормативна, а культурна причина: Якщо 204використовуватись для GET /users/9наступного, що відбудеться в проекті, це те, що хтось вважає, що повернення 204добре для російських методів. І це ускладнює клієнтський код, оскільки замість того, щоб просто перевірити, 2xxа потім розшифрувати тіло, клієнт тепер повинен спеціально перевірити, 204і в цьому випадку пропустити розшифровку тіла. Буд, що замість цього робить клієнт? Створити порожній масив? Чому б цього не було на дроті? Якщо клієнт створює порожній масив, 204 - це форма тупого стиснення. Якщо клієнт використовує nullнатомість, відкриється зовсім інша банка глистів.


5

Twitter використовує 404 зі спеціальним повідомленням про помилку на кшталт "Не знайдено даних".

Посилання: https://developer.twitter.com/en/docs/basics/response-codes.html


2
Microsoft Azure також використовує 404, але користувацьке повідомлення про помилку неможливо під час відповіді на запити HEAD. docs.microsoft.com/en-us/rest/api/resources/resources/…
Майк

3

204 є більш доречним. Особливо, коли у вас є система оповіщення, щоб забезпечити безпеку веб-сайту, 404 в цьому випадку спричинить плутанину, оскільки ви не знаєте, що деякі сповіщення 404 - це помилки утиліти або звичайні запити, але відповідь порожня.


Ви не повинні повертатись 404, якщо у вас є помилка резервного копіювання.
жахливий22

3

Я б сказав, жоден із насправді не підходить. Як було сказано - наприклад, від @anneb, я також вважаю, що частина проблем виникає в результаті використання коду відповіді HTTP для транспортування статусу, що стосується послуги RESTful. Все, що може сказати службі REST про власну обробку, слід транспортувати за допомогою спеціальних кодів REST.

1

Я б стверджував, що якщо сервер HTTP знайде будь-яку службу, яка готова відповісти на запит, на який він був надісланий, він не повинен відповідати HTTP 404 - врешті-решт, щось було знайдено сервером - якщо це прямо не сказано сервіс, який обробляє запит.

Давайте на хвилину припустимо наступний URL: http://example.com/service/return/test.

  • Випадок A полягає в тому, що сервер "просто шукає файл у файловій системі". Якщо його немає, 404правильно. Те саме відбувається, якщо він просить якусь службу доставити саме цей файл, і ця служба каже йому, що нічого з цього імені не існує.
  • У випадку B сервер не працює з "реальними" файлами, але насправді запит обробляється якоюсь іншою службою - наприклад, якоюсь системою шаблонів. Тут сервер не може пред'являти жодних претензій щодо існування ресурсу, оскільки він нічого про нього не знає (якщо тільки не повідомила служба, що обробляє його).

Без будь-якої відповіді служби, яка явно вимагає іншої поведінки, сервер HTTP може сказати лише 3 речі:

  • 503 якщо служба, яка повинна обробляти запит, не працює або не відповідає;
  • 200 в іншому випадку, оскільки сервер HTTP може фактично задовольнити запит - незалежно від того, що служба скаже пізніше;
  • 400або 404вказувати на відсутність такої послуги (на відміну від "існує, але офлайн") і нічого іншого не знайдено.

2

Щоб повернутися до питання: я думаю, що найчистішим підходом було б не використовувати HTTP будь-який код відповіді, окрім сказаного раніше. Якщо служба присутня та відповідає, код HTTP повинен бути 200. Відповідь має містити статус, який служба повертає в окремому заголовку - тут служба може сказати

  • REST:EMPTYнаприклад, якщо його просили шукати що-небудь. і це дослідження повернулося порожнім;
  • REST:NOT FOUNDякщо його просили спеціально для чого-небудь. "Ідентифікатор, подібний до ідентифікації" - це ім'я файлу або ресурсу за ідентифікаційним номером або записом № 24 тощо. - і конкретний ресурс не знайдений (як правило, один конкретний ресурс запитувався і не був знайдений);
  • REST:INVALID якщо будь-яка частина запиту, який він надіслала, служба не визнає.

(зауважте, що я заздалегідь встановив їх за допомогою "REST:", щоб позначити той факт, що, хоча вони можуть мати ті ж значення або формулювання, що і коди відповідей HTTP, вони є що-небудь зовсім інше)

3

Повернемося до вищезгаданої URL-адреси та перевіримо випадок B, коли служба вказує HTTP-серверу, що він сам не обробляє цей запит, а передає його на SERVICE. HTTP обслуговує лише те, що йому передано SERVICE, він нічого не знає про return/testчастину, якою обробляється SERVICE. Якщо ця послуга запущена, HTTP повинен повернутися, 200оскільки він дійсно знайшов щось для обробки запиту.

Статус, який повертається SERVICE(і який, як було сказано вище, хотілося б бачити в окремому заголовку), залежить від того, яку дію очікують насправді:

  • якщо return/testзапитує конкретний ресурс: якщо він існує, поверніть його зі статусом REST:FOUND; якщо цього ресурсу не існує, поверніться REST:NOT FOUND; це може бути продовжено до повернення, REST:GONEякщо ми знаємо, що воно колись існувало і не повернеться, і REST:MOVEDякщо ми знаємо, що воно пішло в голлівуд
  • якщо return/testвважається пошуковою чи фільтрованою операцією: якщо набір результатів порожній, поверніть порожній набір у запитуваному типі та статусі REST:EMPTY; набір результатів у запитуваному типі та статусіREST:SUCCESS
  • якщо return/testце не операція, яку розпізнає SERVICE: поверніть, REST:ERRORякщо вона абсолютно неправильна (наприклад, помилка друку retrun/test), або REST:NOT IMPLEMENTEDякщо вона планується на потім.

4

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

  • Якщо HTTP 404 повернуто, сервер мені каже: "Я не маю поняття, про що ви говорите". Незважаючи на те, що частина REST мого запиту може бути точно в порядку, я шукаю par'Mach у всіх неправильних місцях.
  • З іншого боку, HTTP 200 та REST: ERR повідомляє мені, що я отримав послугу, але щось зробив не так у своєму запиті до служби.
  • З HTTP 200 та REST: EMPTY я знаю, що я нічого поганого не зробив - правильний сервер, сервер знайшов службу, правильний запит до сервісу - але результат пошуку порожній.

Підсумок

Проблема та обговорення виникає з того, що коди відповідей HTTP використовуються для позначення стану служби, результати якої обслуговуються HTTP, або для позначення sth. це не входить до сфери дії самого HTTP-сервера. Через цю невідповідність на питання не можна відповісти, і всі думки піддаються великій дискусії.

Стан запиту, обробленого службою, а не HTTP-сервером, дійсно НЕ повинен (RFC 6919) надаватися кодом відповіді HTTP. Код HTTP ПОТРІБНО (RFC 2119) містить лише інформацію, яку сервер HTTP може надати з власної сфери: а саме, чи було виявлено, що служба обробляє запит чи ні.

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


2

Відповідно до RFC7231 - page59 ( https://tools.ietf.org/html/rfc7231#page-59 ) визначення 404 відповіді коду статусу:

6.5.4. 404 Не знайдено Код стану 404 (Не знайдено) вказує на те, що сервер-джерело не знайшов поточне представлення для цільового ресурсу або не бажає розкривати, що існує. Код статусу 404 не вказує, чи є ця відсутність представництва тимчасовою чи постійною; переважний код статусу 410 (пропав) понад 404, якщо сервер-джерело знає, імовірно, через деякі настроювані засоби, що умова, ймовірно, буде постійною. Відповідь 404 кешована за замовчуванням; тобто, якщо інше не визначено визначенням методу або явними кеш-керами (див. Розділ 4.2.2 [RFC7234]).

І головне, що викликає сумніви, - це визначення ресурсу в наведеному вище контексті. Відповідно до того ж RFC (7231), визначення ресурсу:

Ресурси: ціль запиту HTTP називається "ресурс". HTTP не обмежує характер ресурсу; він просто визначає інтерфейс, який може використовуватися для взаємодії з ресурсами. Кожен ресурс ідентифікується за допомогою Уніфікованого ідентифікатора ресурсу (URI), як описано в розділі 2.7 [RFC7230]. Коли клієнт створює повідомлення запиту HTTP / 1.1, він надсилає цільовий URI в одній з різних форм, як визначено в (Розділ 5.3 [RFC7230]). Коли запит отримано, сервер реконструює ефективний URI запиту для цільового ресурсу (Розділ 5.5 [RFC7230]). Однією з цілей проекту HTTP є відокремлення ідентифікації ресурсів від семантики запиту, що стає можливим шляхом вивірки семантики запиту в методі запиту (Розділ 4) та декількох полів заголовків, що змінюють запит (Розділ 5).

Отже, на мій погляд, код статусу 404 не повинен використовуватися для успішного запиту GET з порожнім результатом (приклад: список без результату для конкретного фільтра)


2

Такі речі можуть бути суб’єктивними, і є цікаві та різноманітні тверді аргументи з обох сторін. Однак [на мою думку] повернення 404 за відсутніми даними є невірним . Ось спрощений опис, щоб зробити це зрозумілим:

  • Запит: Чи можна мати будь-які дані, будь ласка?
  • Ресурс (кінцева точка API): я отримаю цей запит для вас тут [надсилає відповідь потенційних даних]

Нічого не зламалось, кінцева точка була знайдена, і таблицю та стовпці знайдено, тому БД запитувала, а дані "успішно" поверталися!

Тепер - чи має ця «успішна відповідь» дані чи не має значення, ви попросили відповідь «потенційних» даних і ця відповідь із «потенційними» даними була виконана. Недійсні, порожні тощо є дійсними даними.

200 означає, що будь-який запит, який ми зробили, був успішним. Я запитую дані, нічого не пішло з HTTP / REST, і коли дані (хоч і порожні) повернуті, мій "запит на дані" був успішним.

Поверніть 200 і нехай запитувач обробляє порожні дані, оскільки цього вимагає кожен конкретний сценарій!

Розглянемо цей приклад:

  • Запит: Запит таблиці "порушення" з ідентифікатором користувача 1234
  • Ресурс (кінцева точка API): Повертає відповідь, але дані порожні

Ці порожні дані цілком дійсні. Це означає, що у користувача немає порушень. Це 200, оскільки це все справедливо, як тоді я можу зробити:

У вас немає порушень, майте чорничний кекс!

Якщо ви вважаєте це 404, що ви заявляєте? Не вдалося знайти порушення користувача? Тепер граматично це правильно, але це просто неправильно в світі REST, якщо успіх чи невдача стосується запиту. Дані про "порушення" для цього користувача можна було знайти успішно. Є нульові порушення - реальне число, що представляє дійсний стан.


[Весела примітка ..]

У своєму заголовку ви підсвідомо погоджуєтесь, що 200 - це правильна відповідь:

Який правильний код відповіді REST для дійсного запиту, але порожніх даних?


Ось кілька моментів, які слід враховувати при виборі коду статусу, незалежно від суб'єктивності та хитромудрого вибору:

  1. Послідовність . Якщо ви використовуєте 404 для "без даних", використовуйте його щоразу, коли відповідь не повертає даних.
  2. Не використовуйте один і той же статус для більш ніж одного значення . Якщо ви повернете 404, коли ресурс не був знайдений (наприклад, кінцева точка API не існує і т. Д.) , Також не використовуйте його для не повернення даних. Це просто спричинює біль у відповідях.
  3. Розгляньте контекст уважно . Що таке "запит"? Що ви говорите, що намагаєтесь досягти?

1

Кодуйте вміст відповіді загальною перерахунком, яка дозволяє клієнтові вмикати його і відповідно розкладати логіку. Я не впевнений, як ваш клієнт розрізнив би різницю між "даними не знайдено" 404 та "веб-ресурсом не знайдено" 404? Ви не хочете, щоб хтось переглядав користувача Z / 9, і клієнт відмовлявся, ніби запит був дійсним, але даних не повернуто.


1

Чому б не використовувати 410? Це передбачає, що запитуваний ресурс більше не існує, і очікується, що клієнт ніколи не зробить запит на цей ресурс у вашому випадку users/9.

Більш детальну інформацію про 410 можна знайти тут: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html


2
"очікується, що клієнт ніколи не зробить запит", - а що, якщо цей користувач буде створений пізніше, ваша відповідь підказує, що ви можете гарантувати, що цей користувач ніколи не буде, це дуже сміливе припущення і, ймовірно, неправильне
Холлі

Що сказала Холлі. Додамо до неї: Навіть у випадку, якщо користувач існував та видалявся, 410 помиляється, бо що робити, якщо користувач не визначився? (Який вид - це окремий випадок, який створюється пізніше.)
Крістіан Худжер

бо 410 має бути постійною ситуацією. restapitutorial.com/httpstatuscodes.html
Akostha

1

Сумно, що щось таке просте і чітко визначене стало "думкою, заснованою на цій думці".

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

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

  • / user / 9 - єдине ціле: ID USER = 9
  • / користувачів - єдине ціле: СПИСОК усіх користувачів
  • /media/x.mp3 - єдине ціле: медіафайл, який називається x.mp3
  • / пошук - єдине ціле: динамічний ЗМІСТ, заснований на парамах запитів

Якщо сервер знайде ресурс за вказаною URL-адресою, не має значення, який його вміст - 2G даних, null, {}, [] - доки він існує, це буде 200. Але якщо така сутність є не відома серверу, очікується повернути 404 "Не знайдено".

Здається, одна плутанина пов'язана з розробниками, які думають, що якщо програма має обробник певної форми контуру, це не повинно бути помилкою. В очах протоколу HTTP не має значення, що сталося з внутрішніми серверами (тобто, відповів маршрутизатор за замовчуванням або обробник для певної форми шляху), доки на сервері немає відповідного об'єкта на сервері запитувана URL-адреса (що вимагає MP3-файл, веб-сторінку, об’єкт користувача тощо), яка повертає дійсний вміст (порожній або іншим способом), він повинен бути 404 (або 410 тощо).

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

Приклад 1:

  • Немає даних: / користувачі повертають 200 ОК, тіло: [], оскільки ніхто ще не зареєструвався
  • Жодна сутність: / користувачі не повертають 404, тому що немає шляху / користувачів

Приклад 2:

  • Немає даних: / користувач / 9 повертає повернення 200 ОК, тіло: {}, оскільки ідентифікатор користувача = 9 ніколи не вводив свої особисті дані
  • Жодна сутність: / user / 9 не повертає 404, оскільки немає ідентифікатора користувача = 9

Приклад 3:

  • Немає даних: / search? Name = Joe повертає 200 ОК [], оскільки в БД немає Джо
  • Немає сутності: / search? Name = Joe повертає 404, оскільки немає шляху / пошуку

0

404 буде дуже заплутаним для будь-якого клієнта, якщо ви повернетесь лише тому, що даних у відповідь немає.

Для мене Код реакції 200 з порожнім корпусом достатньо, щоб зрозуміти, що все ідеально, але немає даних, що відповідають вимогам.



0

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

Очікується, що стан 200 міститиме дані про ресурси - тож це не правильний вибір. Статус 204 повністю означає щось інше і не повинен використовуватися як відповідь на GET-запити.

Усі інші існуючі статуси з тієї чи іншої причини не застосовуються.

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

Це буде статус 2xx, оскільки не знайти ідентифікатор не слід вважати клієнтською помилкою (якби клієнти знали все, що є в БД сервера, їм би не потрібно було нічого запитувати на сервер, чи не так?). Цей спеціальний статус стосуватиметься всіх питань, які обговорювались із використанням інших статусів.

Питання лише в тому, як змусити RFC прийняти це як стандарт?

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