Чи слід використовувати коди статусу HTTP для опису подій на рівні програми


54

Кілька серверів, з якими я мав справу, повернуть HTTP 200 для запитів, які клієнт повинен вважати помилкою, з тілом як "успіх: помилка".

Мені це не здається належним впровадженням HTTP-кодів, особливо у випадках невдалої аутентифікації. Я прочитав коди помилок HTTP досить коротко підсумовані, оскільки "4xx" вказує на те, що запит не слід робити знову до зміни, тоді як "5xx" вказує на те, що запит може бути неправдивим і може бути повторним, але був невдалим. У цьому випадку 200: вхід не вдалося, або 200: не вдалося знайти цей файл, або 200: відсутній параметр x, безумовно, здається неправильним.

З іншого боку, я міг бачити аргумент, що "4xx" повинен вказувати лише на структурну проблему із запитом. Тож належним чином повернути 200: поганий користувач / пароль, а не 401 несанкціонований, оскільки клієнту дозволяється робити запит, але це трапляється неправильно. Цей аргумент можна узагальнити так, якби сервер зміг обробити запит і визначитись, код відповіді повинен бути 200, і клієнт повинен перевірити орган для отримання додаткової інформації.

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


9
success: falseозначає, що запит не вдався, і ви це знаєте. Це має бути 500. Щось на зразок вашого неправильного імені користувача / пароля було б 401. Це не так неоднозначно.
Піт


4
Це одне з тих питань, які можуть викликати релігійні війни, на мою думку. Для API RESTful відповідь зрозуміла, але є й інші види API, де HTTP трактується просто як транспортний шар, і в цих випадках помилки програми не повинні кровоточити на цьому шарі.
Gort the Robot

5
Коли я справді не впевнений, який статус http повернути, завжди спокусливо піти з 418 "Я чайник".
joshp

1
Прикладом є кілька запитів та відповідей . Випікання не є справою спокою; однак проблеми практичної ефективності часто потребують певної підтримки для вирішення проблем з елегантністю.
rwong

Відповіді:


35

Цікаве запитання.

В основному ми можемо звести це до правильного способу класифікації речей, аналогічних шарам OSI. HTTP зазвичай визначається як протокол рівня програми, а HTTP справді є загальним протоколом клієнт / сервер.

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

Проблема з спробою підсилити протокол HTTP для обробки потоків, що стосуються додатків, полягає в тому, що вам залишається один з двох варіантів: 1) Ви повинні зробити свою логіку запиту / відповіді підмножиною правил HTTP; або 2) Ви повинні повторно використовувати певні правила, і тоді відокремлення проблем має тенденцію до нечітких. Спочатку це може виглядати красиво і чисто, але я думаю, що це одне з тих дизайнерських рішень, про які ви, в кінцевому рахунку, шкодуєте, коли ваш проект розвивається.

Тому я б сказав, що краще бути чітким щодо розділення протоколів. Нехай сервер HTTP і веб-браузер роблять свою справу, і програма нехай робить свою справу. Додаток повинен вміти робити запити, і йому потрібні відповіді - і його логіка щодо того, як запитувати, як інтерпретувати відповіді, може бути більш (або менш) складною, ніж перспектива HTTP.

Інша перевага цього підходу, яку варто зазначити, полягає в тому, що програми, як правило, не повинні залежати від базового транспортного протоколу (з логічної точки зору). Сам HTTP змінився в минулому, і тепер ми починаємо HTTP 2, слідуючи SPDY. Якщо ви вважаєте, що ваш додаток не є додатком додатка для HTTP-функцій, ви можете застрягнути там, коли перейдуть нові інфраструктури.


8
Дуже проникливий. Найсильніший аргумент тут - невідповідність між кодами статусу HTTP та зворотними значеннями програми. Це може стати кошмаром на довгостроковій перспективі. Крім того, я дуже підтримую розділення проблем між транспортом (HTTP) та корисним навантаженням (дані програми). Якщо ви введете неправильну URL-адресу кінцевої точки служби, ви отримаєте 404. Якщо ви попросите службу про неіснуючий товар, ви отримаєте повідомлення про додаток (можливо, з додатковою інформацією, яку ви можете використовувати для вирішення проблеми).

2
Якщо ви неправильно введете URL-адресу, ви можете навіть не опинитися на потрібному сервері, і тоді все може статися.
gnasher729

Це приємно нюансований вигляд. Я думаю, що проблема перетворення HTTP на псевдотранспортний шар є справжньою проблемою при визначенні. Я найчастіше сам стикаюся з цим питанням, коли у вас є сервер nginx або apache, який знаходиться поруч із сервером nodejs, де проксі має правила для надсилання цих кодів, і стає питання, чи підходить цей сервер відповідно до стандарту. У деяких із цих випадків може бути причина дизайну, щоб не надсилати код помилки, оскільки nginx може інтерпретувати його як "резервний вихід".
Каган Маттсон

4
Я згоден. Немає нічого поганого в повідомленні про помилку на рівні додатку у відповіді HTTP 200. Значення 200 вказує на те, що сам HTTP-запит / відповідь був успішним, нічого не кажучи про його вміст або семантику рівня додатків, на яку взивались тоді.
Гонки легкості з Монікою

22

Це питання на основі думки, але в будь-якому випадку.

Те, як я це бачу, 200 може подати "м'які помилки". Що стосується створення API, я намагаюся розрізняти ці "жорсткі помилки".

"М'які помилки" подаватимуться з кодом статусу 200, але містять опис помилки та статус успішності false. "М'які помилки" трапляться лише тоді, коли результат буде "як очікувалося", але не буде успіхом у найсуворішому сенсі.

Важливо зазначити, що "м'які помилки" - це більше натяк на реалізатора. Для цього важливо також надати додаткову інформацію про помилку, таку як людське повідомлення про помилку та / або якийсь код, який можна використовувати для надання кінцевому користувачеві зворотного зв'язку. Ці помилки надають реалізатору (і кінцевому користувачеві) більше інформації про те, що сталося на стороні сервера .

Наприклад, у вас є API з функцією пошуку, але під час пошуку результати не даються. Це не помилково, але це також не «успіх», не в суворому розумінні визначення.

Приклад відформатований як JSON:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

З іншого боку, "жорсткі помилки" подаватимуться з кодом статусу, який рекомендовано для помилки. Користувач не ввійшов у систему? - 403 / 401. Неправильний вхід? - 400. Помилка сервера? - 50X. І так далі.

Знову ж таки, це трохи ґрунтується на думці. Деякі люди хочуть ставитися до всіх помилок однаково, "важко помиляючись" у всьому. Немає результатів пошуку? Це 404! З іншого боку монети немає результатів пошуку? - Це як очікувалося, помилок немає.

Ще одним важливим фактором, який слід врахувати, є, наприклад, ваша архітектура; якщо ви взаємодієте зі своїм API за допомогою XHR запитів JavaScript та jQuery або AngularJS. Ці "жорсткі помилки" доведеться обробляти окремим зворотним викликом, тоді як "м'які помилки" можна обробляти за допомогою "успіху" -викликання. Нічого не порушуючи, результат все одно «як очікувався». Потім клієнтський код може переглянути стан успіху та код (або повідомлення). І роздрукуйте це для кінцевого споживача.


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

1
Є багато речей, які потрібно враховувати. Все залежить від впровадження API. Знову ж таки, трохи на основі думки, а також до того, що API визначає як "успіх" та / або "помилка". "success": false-Flag це скоріше натяк на реалізатор , що що - то трапилося. Зазвичай він повинен відповідати внутрішньому коду статусу. Або "code": "NORESULTS"чисельний код - незалежно від того, хто створює API API. Це здебільшого, тому той, хто реалізує API, може вивести інформацію про те, що сталося на сервері.
die maus

15

Є два аспекти API: намагання впровадити API та намагання всіх клієнтів правильно використовувати API.

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

Створюючи API, слід переглянути, що клієнту найпростіше обробити. Якщо клієнт надсилає добре сформований запит, і ви можете робити те, що просить вас зробити, тоді вам слід дати відповідь у діапазоні 200 (є деякі випадки, коли число, яке не є 200, у цьому діапазоні є відповідним).

Якщо клієнт просить "дати мені всі записи, як ...", а там нуль, то 200 з успіхом і масив нульових записів цілком підходить. Випадки, про які ви згадуєте:

"Не вдалося ввійти" зазвичай має бути 401. "Не вдалося знайти файл" має бути 404. "Відсутній параметр x" повинен бути приблизно 500 (насправді 400, якщо сервер визначить, що запит поганий, і 500 якщо сервер повністю збентежений моїм запитом і не має уявлення, що відбувається). Повертати 200 у цих випадках безглуздо. Це просто означає, що як автор клієнта, я не можу просто подивитися на код статусу, я також повинен вивчити відповідь. Я не можу просто сказати "статус 200, чудово, ось дані".

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

Зрештою, існує десяток-два коди статусу для вирішення багатьох різних ситуацій, і ви повинні їх використовувати.


3
Під час підключення до API, я особисто отримав би 200 на "файл не знайдений" при підключенні до дійсної кінцевої точки, оскільки тоді моя обробка HTTP не повинна кровоточити в шар, який обробляє API поверх нього.
whatsisname

4
"Відсутній параметр x" повинен бути 400 BAD_REQUEST, оскільки клієнт робить щось не так. 500 INTERNAL_SERVER_ERROR слід зарезервувати для випадків, коли сервер робить не так. Значення 500 означає, що клієнт, можливо, зможе спробувати ще раз. 400 означає, що хтось повинен піти виправити клієнта.
Gort the Robot

1
Якщо ви пишете інтерфейс RESTful, URL-адреса ідентифікує конкретний об'єкт, тому 404 є відповідним. Концептуально те саме /customers/premium/johndoe.jsonстосується клієнта, який не знаходиться в базі даних, і якщо він /files/morefiles/customers.htmlпосилається на сторінку, яка не знаходиться у файловій системі.
Gort the Robot

@whatsisname Те, що ви говорите, має сенс, оскільки тоді незрозуміло, чи погана кінцева точка чи ресурс не існує. Ви також можете стверджувати, що кінцева точка є дійсною чи ні, за цією адресою не існує жодного ресурсу, тому а 404в обох випадках є правильним.
Піт

2
Одне, що я не бачив, це те, що, коли ви надсилаєте помилки програми на коди статусу HTTP, ви можете втратити інформацію. Якщо додаток просто повертає 404 і нічого іншого, ви не знаєте, чи це тому, що ваш API повернув 404, або тому, що сервер не зміг знайти файл. Це може додати ще один крок до налагодження.
AmadeusDrZaius
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.