Про три символи, на які може послати сервер

Усі статті, обговорення, новини про Front-end — в одному місці. Підписуйтеся на телеграм-канал!

Ви стикаєтесь із ними щодня, щохвилини, явно чи неявно. Тисячі коротких тризначних кодів повертаються до ваших пристроїв у відповідь на бажання почитати новини, подивитися фільм чи написати змістовну й вагому думку під час урівноваженої, цивілізованої дискусії. Що ж це за загадкові числові комбінації і яку роль вони відіграють у житті сучасного інтернету? Пропоную докопатися до істини разом.

***

...того року Італія здобуває світову першість, здолавши збірну Західної Німеччини з рахунком 3:1, Майкл Джексон випускає найбільш продаваний музичний альбом усіх часів Thriller, у продажі з’являються CD-диски, а в космос відправляється Space Shuttle Columbia. Це — 1982-й. І саме цього року виходить RFC 821, у якому визначається специфікація протоколу передачі електронної пошти мережею «Інтернет». До чого тут це, спитаєте ви? Все просто: саме в цій специфікації вперше з’являються ті самі тризначні коди, принцип яких пізніше запозичить той самий Тім Бернерс-Лі, всебатько сучасного інтернету.


Користувач ПК читає пошту. Чи електронну — до кінця не зрозуміло

Самі коди трохи відрізнялися від звичних нам HTTP-статусів, однак дещо лишилося незмінних з тих давніх часів. Наприклад, уже тоді група кодів 2xx означала успішне виконання команди, а різні статуси групувалися за першою цифрою коду. Згодом цей принцип перекочував і до протоколу передавання файлів FTP. До речі, цікавий факт: група 1xx з’явилася саме в специфікації FTP, а от у SMTP її просто не було.

Як не було цієї групи статусів і в протоколу HTTP аж до версії HTTP/1.1. Ба більше, у найпершої версії, HTTP/0.9, статусів не було зовсім! Це був суворий час, коли HTTP мав лише один GET-метод, а якщо ресурс, який ви запитували в сервера, не існував, то ви попросту не отримували ніякої відповіді.

І лише з версією HTTP/1.1 список статусів нарешті набув звичного нам стану з п’ятьма групами:

  • Інформаційні повідомлення 1xx: вказують на те, що запит отримано й обробка продовжується.
  • Успішні відповіді 2xx: повідомляють про успішне виконання запиту.
  • Повідомлення про перенаправлення 3xx: сигналізують, що клієнт має виконати додаткові дії для завершення запиту.
  • Помилки клієнта 4xx: кажуть про проблеми з боку клієнта, що заважають виконати запит.
  • Помилки сервера 5xx: вказують на те, що сервер не зміг виконати запит через внутрішню помилку.

Аби зрозуміти, що ж означають ці групи повідомлень, можна уявити собі ситуацію, коли ви питаєте в перехожого про шлях до бібліотеки. Ви виступаєте в ролі клієнта, наприклад браузера, а перехожий — у ролі сервера. Отже, якщо у відповідь на ваше запитання його адресат робить задумливе лице, чухає потилицю і бурмоче: «Зара, зара, секунду», то це буде відповідь з першої групи 1xx.

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

У разі, якщо на ваше запитання ви отримуєте щось на кшталт «біжи три дні за оленем, скачи два дні за зайцем, повзи один день за змією, тоді дістанешся річки, а на березі цієї річки сидітиме старий та мудрий дід — от йому мізки й грай!», то, швидше за все, вас було перенаправлено за допомогою відповіді з третьої групи 3xx.

Коли ж ваш сервер із криком «Сишиш, ти, бль...!» просто бʼє вас у лице, а потім по нирках, імовірно, ви звернулися не до того перехожого й не тими словами. Тобто це помилка клієнта з четвертої групи статусів 4xx. І повторювати той самий запит, певно, не варто.


Помилка клієнта. Можливо, фатальна

А якщо у відповідь на ваше питання перехожий, довірливо дивлячись вам в очі, мовчки обригався, то тут усе просто — це 5xx.

Тож для чого саме призначені ці коди статусів, та який у них сенс?

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

Наприклад, якщо сервер на певний запит відповість 404, то ми знатимемо як мінімум дві речі: цей ресурс потенційно відкритий і за цим посиланням інформації, що нас цікавить, не існує. В прикладі з бібліотекою це звучатиме як «нема у нас бібліотеки». А якщо ж відповідь буде 401, то це означатиме, що перехожий вас не знає і відповідати через це не бажає. Людською мовою це виглядало б так: «Ваші документи, а потім будете питать». Якщо ж і після того, як ви покажете вашу «Дію», він скаже, що «де бібліотека, вам знать не положено», то це однозначно статус 403.

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

Взагалі, правильна обробка статус-кодів є дуже важливою у веброзробці: вона дозволяє як покращити зручність ваших сайтів для користувачів, так і більш акуратно й точно реагувати на різноманітні сценарії. А якщо обробляти усі помилки через плашку «Ooops, something went wrong!», то ви встрелитесь шукати, що саме пішло не так під час розробки й налагодження, а ваші користувачі з великою ймовірністю скажуть: «Ooops, you did it again» — і стрімко поскачуть у напрямку конкурента.

Окремо хочеться накликати усі біблійні напасті на голови тих, хто відповідає на всі можливі події простим, старим добрим 200, навіть якщо в цей час насправді у них попадали усі бекапи, а на сервер наклав Ґодзілла. А фактичну відповідь кладуть десь у пʼятнадцятий рівень вкладеності обʼєкта-відповіді. Знаєте, що мені це нагадує? Ніби коли зраночку світить сонечко, співають пташки, ви виходите на кухню, а там уже сидить ваш партнер — і ви відчуваєте, що щось не так. Й у відповідь на запитання «Шось сталось?» — фраза, від якої холоне в жилах: «ВСЕ НОРМАЛЬНО». А ви ж розумієте, що нічого там не нормально, але реальну причину такої відповіді сервер вам не каже, бо у нього «все нормально». І от як ми маємо таке обробляти на клієнті, га?! Тому робіть, будь ласочка, нормальні відповіді за специфікацією. Communication is a key.


А це ще клієнт навіть у сервера нічого й не питав!

Специфікація HTTP постійно розвивається, доповнюється, і, як не дивно, часом позбувається неактуальних кодів чи змінює значення наявних. Наприклад, код 305 Use Proxy було вилучено через проблеми безпеки та потенційні загрози, пов’язані з неправильним використанням проксі-серверів. А код 306 узагалі ніколи не був визначеним, не те що використовуваним, тож його теж позбулися без жалю. Така ж доля, підозрюю, чекає й на код 402 Payment Required, який досі залишається «зарезервованим для майбутнього використання». Його призначення — вказувати на те, що для доступу до ресурсу потрібна оплата, але стандартних протоколів його використання не розробили.

До речі, поширеною думкою є те, що жартівливий код 418 I’m a Teapot є частиною специфікації HTTP. Мушу вас розчарувати: він — частина стандарту Hyper Text Coffee Pot Control Protocol (HTCPCP), хоча часто вказаний у переліках кодів до HTTP. Так от, цей код зʼявився в жартівливому RFC 2324, опублікованому 1 квітня 1998 року. Він описує HTCPCP, який є пародією на інші інтернет-протоколи, й призначений для управління кавоварками через інтернет.

А от код 451 Unavailable for Legal Reasons дійсно є частиною специфікації HTTP з грудня 2015 року. Хто відразу не упізнав, то це пряме відсилання до роману неперевершеного Рея Бредбері «451 градус за Фаренгейтом» — про суспільство, де книги заборонені та підлягають спаленню. Відповідно, код 451 символізує цензуру або правові обмеження на доступ до інформації.

Які ж висновки можна зробити з цього нашого невеличкого екскурсу?

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

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


Дякую за увагу, з вами був Сергій Бабіч та Дивовижний світ веброзробки, і якщо вам сподобалась ця стаття, прошу підписатися на мій ютуб канал, а також обовʼязково залишити тут коментар. Можна навіть образливий, або такий, де ви кажете, що це все мають знати діти уже в дитсадку, і взагалі, ще би про <div> написав.

...а я й пишу...

👍ПодобаєтьсяСподобалось95
До обраногоВ обраному16
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Як і підозрював, достатньо коментів «та кому нафік ті коди потрібні», «5 кодів достатньо кожному погромізду».
PS.
4xx коди в API використовуємо досить широко, в т.ч..402 (у користувача немає чи заекспайрена ліцензія)
Щодо «дивіться що там в респонз боді» — devops тулам (і не тільки) набагато простіше чекнути респонз код і зрозуміти що далі рухатись не варто, ніж брати специфікацію резпонз боді і її парсити.

Бо всі на цю спецефікацію кладуть білт, скільке не прикручував сторонні апішки —

дивіться що там в респонз боді

щоб зрозуміти що там так, чи не так.

Треба додати ще щось типу
HTTP 299 Disappointed: The server has accepted your request but thinks you can do better

402 Payment Required — улюблений. можна у відповіді давати номер картки!

Використовуємо 200, 401, 404, 500, усе інше і нафік не впало, і навіть не планую щось більше використовувати, нікому оце вилизування цих кодів не цікаво а головне не потрібно. Для інтерфейсу є три основних кейси:
1 — 200 запит ок, це коли сервер повератє данні, або мовчки зберіг\оновив данні,
2 — 401 треба логін
3 — 404\500 щось не так.
Все інше йому насрати.

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

Та ну лан, бот, ну хоч ти не позорся серед інших неуків )

301/302/304, 403, 412, 100, 101, як мінімум з голови можу сказати що регулярно потрібні в житті кожному погромізду

Я навіть не памятаю навіщо вони і що вони роблять.

Чудова стаття! І посміявся і щось технічне для себе нагадав.

Дякую! Приємно, що такий формат заходить )

Найкраща стаття на доу за останні (крайні) роки.

Чудовий виклад! Дякую за публікацію😊

А чому досі не зробили щось у вигляді універсального

function: onresponse(resultCode) {
  switch resultCode {
  case 200 : callback200() 
  case 404 : callback404() 
...
  default : {
   callbackDontPanick() 
  }  
}

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

Так зробіть) Ніхто ж не заважає. Або можете поконтрібьютати в існуючі опенсорс ліби

Бо... клієнт. Клієнти різні, бачення різні. Одні хочуть на 402 викатити оду про те що варто купити їх продукт. Інші на всі помилки просять видавати «oops». А ще часто в одному проєкті навіть на одній сторінці відповіді з одним кодом мають різне відображення на UI.

Кожен раз коли проектую апі, й починається обговорення який http статус повертати, я завжди схиляюсь до думки — а чи не пофіг? HTTP апі використовується для фронта в 95% й 5% якісь серверні інтеграції.
В випадку фронта (та й серверу в принципі теж) — його цікавть лише три стани й два формати респонсу («ок» та «помилка»):
— все ок (200) — можна показувати юзеру контент з результатом
— щось не ок й юзер може на це повпливати (змінити дані в формі) — 400 — показати помилку (ладно, хай буде 401 ще — на них часто редірект на логін вішають)
— все інше. (зазвичай 500, але туди ще й 404 й інші попадають, бо що юзер зробить якщо фронтенд викликає неіснуючий апі?) — відображається Server error.

Й здебільшого саме такий розподіл зручний, бо біільшість клієнтських ліб автоматично розділяють саме ці стани — return response (2xx) та throw exception (4хх) й буває іноді окремий експешн для 5xx.

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

Тим часом специфікація: «Ну та, ну та, пішла я нахєр»

Так а толку з специфікації? Чисто перфекціонізм свій потішити, що в мене тут все по специфікаціям. Та й розроблялась вона фіг знає коли.

специфікації — вони не для того, щоб своє тішити, вони для того, щоб іншим зрозуміло було.

Я не за специфікації взагалом, тільки конкретно за специфікацію по статусам HTTP. В 99% випадків ніхто не дивиться на статус, а одразу читає помилку з response body.

ага. Але, імхо, це не причина ними нехтувати. У мене не великий досвід роботи з чужими апі, але був бачив, як повертали 400 з даними, або 200 з помилкою. на «тій стороні» хлопці (чи саїби чи ефенді) теж здивовано на мене дивилися "та дивися на body, чого ти до тих статусів причепився?

як повертали 400 з даними, або 200 з помилкою

Ні, ну це так, вже качелі в іншу сторону — повне нехтування специфікацією ) Я все ж таки за баланс, там де нам це допомагає — ми юзаємо, там де заважає й заплутує — не використовуємо.

Можна й на одних 200х зробити зручне апі. А можна все по специфікаціям, але користуватись цим буде просто неможливо.

От наприклад, Сергій, в мене немає даних до яких в тебе немає доступу. Це 404 чи 403?

403. Бо в першу чергу немає доступу. І далі ти запит не пускаєш. А про те, що 404, ми маєм дізнатися лише у випадку якщо є доступ
Очевидно ж.

Так, це виглядає слушно.
Розглянемо тепер такий перебіг подій. Оскільки ми отримали саме 403, а не 401, це означає що аутентифікацію пройдено, і ми тосно знаємо куди користувач має доступ, а куди ні.
Але тепер користувач має можливість проаналізувати структуру системи
Накшталт, «а чи є в них розділ /admin?»
Update: Тут є один момент, який потребує пояснення. Якщо ми вирішили видавати 403 незалежно від того існує ресурс чи ні, то це знівелює самий сенс коду 404. А якщо будемо видавати 404 там де нічого захищати, то покажемо за допомогою 403 всі місця, які ми захищаємо.

чому би ми вирішували віддавати Forbidden замість Not Found?
імхо
якщо робиш запит на /phpAdminXyr32 а його немає, то 404. Якщо є, але доступ обмежено і ти не авторизований — 401, якщо авторизований, але не вистачає прав — 403.
Нуу так, засвітили існування пхпАдміна. Якщо ми віддаватимемо 200 {"error": "Forbidden"} ми так само «спалимо» існування пхпадміна.

Якщо немає доступу до адмінки і виконуєш DELETE /admin/users/42, то отримуєш 401/403 незалежно від того, чи є юзер 42, бо доступу немає в принципі до адмінки і глибше запит не йде.
Якщо доступ до юзерів є, але немає прав на видалення, то 403
Якщо є усі права, але юзера немає — 404

Давайте визначимось.
Аутентифікований — це той кого ми визначили хто це
Авторизований — це той, хто має права
Це за визначенням цих слів.
Тож фраза

авторизований, але не вистачає прав — 403

не має сенсу

Авторизований — це той, хто має права

хмм. точно? Я завжди сприймав це як «людина, чиї права ми можемо визначити»
Автентифікували — це Олександр
Авторизували — Олександр має права на перегляд і редагування юзерів.
На спробу видалення юзера авторизований олександр отримує forbidden.

хмм. точно? Я завжди сприймав це як «людина, чиї права ми можемо визначити»

Точно точно. Продовжуючи приклад:
1. Олександр автентифікований
2. Олександр авторизований на переглад і редагування юзерів — дозволено
3. Олександр НЕ авторизований на видалення юзерів — заборонено

2 і 3 це і є перевірка авторизації.
Згоден, у попередньому коменті я сформулював недостатньо чітко. перефразую
якщо процес авторизації відбувся, але не вистачає прав — 403

От бачите, вже почали писати інше ніж кажете Ви, і інше ніж кажу я. Тобто «не всьо так адназначна»

Фронт може не використовувати, але чи буде там тільки фронт, а не якась стороння аплікація? Я стараюся переюзати те саме апі часто, бо лінивий.

HTTP апі використовується для фронта в 95% й 5% якісь серверні інтеграції.

Навпаки + мобільні клієнти + десктопні клієнти + будь-які інші клієнти інтегровані через лібу-обгортку апішки.
Ви щось складніше «Hello World» SPA писали?

Навпаки + мобільні клієнти + десктопні клієнти + будь-які інші клієнти

Тут фронт = будь який UI для юзера.

Ви щось складніше «Hello World» SPA писали?

Так, й мене дуже бісить коли обробка помилок перетворюється в макарони в якому наміішані if’и для різних статусів, ще й різні формати body для помилок, ще й десь меседж одразу з бека приходить, а десь треба меседж резолвити зі статусу в body, а десь зі статусу HTTP, ще й як завжди щось забули. Й це все дублюється для різних клієнтів. Й це все робиться для кожного ендпоінту, бо всі вони різні помилки повертають.

В тому що я описав обробка помилок це звичайний try-catch, де помилка яку показуємо юзеру — це або помилка з body (локалізацію можна на фронті по enum на errorType з body — бажано щоб він був з типом string аля USER_NOT_FOUND, а не int, можна на беку одразу поле message слати додатково), або ServerError по дефолту, якщо якась хрінь повернулась.

Фронтопроблеми. Ще раз повторюся, HTTP використовується для багатьох задач, які не пов’язані безпосередньо з UI.
Викидувати серверні помилки користувачу не сильно гарна ідея, якщо ви не контролюєте ту частину серверного коду, з якою комунікуєте.
Спробуйте tRPC. Хоча у мене таке відчуття, що ви свої ідеї десь там і берете.

Ще раз повторюся, HTTP використовується для багатьох задач, які не пов’язані безпосередньо з UI.

Й для цього HTTP статусів не вистачає, все одне потрібний більш детальний «код помилки», все одно дивимось в body, тому я й раджу:

enum на errorType з body — бажано щоб він був з типом string аля USER_NOT_FOUND

А при такому підході додавати до цього статус HTTP — ну можна. Але все одно обробка буде з розряду if 4хх = parseErrorTypeFromBody(). Тобто HTTP статус буде просто ігноруватись.

і матимемо шо? матимемо, що десь прилітатиме 404 чи 502 від нжинкса, або 401 чи 302/301, або 500 якщо впаде десь несподівано. І от через це і мусиш обмазувати ifами не тільки body, а й коди.

Ок, давайте подумаємо.
Моніторимо ми таку апішечку, хочемо узнати який відсоток викликів крашаться. Треба нам 500-а? Мабуть треба. SLA і все таке.
403, 404 треба бачити? Ну щоб розуміти, що ніхто не довбиться в якийсь лівий ресурс.
401 — обов’язково. Індикатор проблем з аутентикацією, а також можливий початок ддосу чи інших веселих речей.
400? О це вже для клієнта, будь-який формат, помилки валідації, кривих рук та кривої голови. Нас це не цікавить.

«HTTP апі використовується для фронта в 95% й 5% якісь серверні інтеграції.» А ви про мікросервіси чули колись?

Там воні іще менш потрібні ))) Закину меседж в сервіс бас і воно працює. Http запити то коли треба звичайний селект данних зробити, авторизація\автентифікація по серві прінціпал, логи в ажур монітор, щоб закинути назад на фронт користувачеві для того є Web PubSub, сам же реакт лежить в CDN...чи ви сидите і колупаете оці Http коди в мікросервісах? )))
PS у AWS все те саме тільки з іншими іменами.

Ось іще хороше пояснення http.cat

Отлично написано, пиши ещё! Может, про DNS или HTTPS?

якщо ти не можеш пояснити проблему 5-ти річній дитині, то ти сам в ній не розбираєшся

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

І тут команда індусів каже, що повертайте завжди 200, бо наша апка не вміє оброблювати інші. А вже в середині респонза зробіть об’єкт з атрибутом status ))

Хреново когда эти индусы — наши родные украинцы

Ну в принципі є протокол JSON-RPC, не те щоб він мені подобався, так намагаюсь знайти виправдання )

главне не забув — 418 🫖

Років 16 тому у DOU були фірмові футболки 200 ОК і 402 Payment required
s.dou.ua/...​torage-files/t-shirts.png

А реально используются разве что 200, 400, 401, 403, 404, 500. Теперь спустя годы, в gRPC их вообще нет за ненадобностью.

Не используются, надо просто клиент исправить при переносе функционала. Тем более при редиректе получается лишний посредник.

класна стаття, про 451 дійсно цікава пасхалка)))

Якщо ця публікація набере 50 вподобайок, обіцяю зробити відео.

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

1xx hold my beer
2xx ok
3xx over there
4xx you have a problem
5xx i have a problem

Підписатись на коментарі