Введение: четыре кода, которые путают почти все

«Чем 401 отличается от 403?» — вопрос, с которого собеседование по сети начинает идти вниз. Не потому, что это сложно, а потому, что ответ «401 — это нет доступа» почти всегда неверный.

HTTP-статусы — первая тема, которую проверяют в сетевом блоке: её можно спросить без кода и без знаний конкретного проекта. И именно на простых вопросах кандидаты теряют баллы — путают аутентификацию с авторизацией или не знают, что 404 иногда отдают намеренно.

Разберём четыре кода из заголовка по официальным определениям RFC 9110, добавим классы статусов и покажем, как обрабатывать ошибки в Android.

Классы статусов

Каждый код трёхзначный, и первая цифра определяет класс ответа. С этого начинают почти любой вопрос про HTTP:

  • 1xx — информационные. Сервер принял запрос и продолжает обработку: 100 Continue, 101 Switching Protocols.
  • 2xx — успех. Запрос выполнен: 200 OK, 201 Created, 204 No Content.
  • 3xx — перенаправления. Клиенту нужно обратиться по другому URI: 301, 302, 308.
  • 4xx — ошибки клиента. Запрос неверный или прав недостаточно: 400, 401, 403, 404, 429.
  • 5xx — ошибки сервера. Сервер не смог выполнить запрос: 500, 502, 503, 504.

Короткий ответ на собеседовании

Класс определяется первой цифрой: 2 — успех, 3 — редирект, 4 — ошибка клиента, 5 — ошибка сервера. Грубо: 4xx — «проблема на нашей стороне», 5xx — «проблема на стороне сервера».

Полный список кодов с определениями удобно освежить в справочнике MDN — там же есть пояснения, которые часто цитируют на собеседованиях.

401 и 403: аутентификация против авторизации

Главная пара путаницы — 401 и 403. Разница простая: 401 — «кто вы?», 403 — «не пущу».

По RFC 9110, 401 означает, что запрос не выполнен, потому что не хватает корректных учётных данных (authentication credentials) для целевого ресурса: сервер не знает, кто к нему обратился, или не доверяет тому, что клиент прислал. Название кода вводит в заблуждение — «Unauthorized», но по смыслу это unauthenticated, «не аутентифицирован». MDN прямо пишет об этой путанице: клиент должен сначала представиться — прислать токен, сессию или логин с паролем.

Детали про 401:

  • При 401 сервер обязан прислать заголовок WWW-Authenticate с описанием способа аутентификации.
  • Если запрос уже содержал учётные данные, 401 означает, что они были отклонены.
  • Классика в API: истёкший или невалидный токен → 401. В Android после него обычно отправляют на экран входа или обновляют токен.

403, по определению RFC 9110, — сервер понял запрос, но отказывается его выполнять. Личность клиента серверу уже известна, а прав на ресурс недостаточно:

  • 403 — это про права доступа: роль пользователя, границы подписки, административные ограничения.
  • Если запрос содержал учётные данные и они не подошли для этого ресурса — тоже 403.
  • Спецификация говорит прямо: клиент не должен автоматически повторять запрос с теми же учётными данными — результат не изменится.

И деталь, которую любят интервьюеры: сервер может намеренно отвечать 404 вместо 403, чтобы не раскрывать существование ресурса. Например, API не хочет показывать, что endpoint с чужими данными вообще существует.

Частая ошибка: «401 — у пользователя нет прав». Нет: нет прав — это 403. Запомните пару: 401 — аутентификация («кто вы?»), 403 — авторизация («не пущу»).

Класс ошибок клиента

4xx — самый частый класс в практике: 400, 401, 403, 404, 405, 429. Вопрос «какой класс у 4xx» — разминка, а «чем 401 отличается от 403» — уже проверка понимания.

404 Not Found: «не нашёл (или не скажу)»

Определение: сервер не нашёл текущее представление целевого ресурса — или не хочет раскрывать, что оно существует. Вторая половина важна: 404 не всегда означает, что ресурса физически нет.

Типичные сценарии:

  • Неверный URL или endpoint, которого не существует.
  • Ресурс удалён или никогда не существовал: в API — запрос конкретного объекта по несуществующему id.
  • Сервер скрывает существование ресурса от неавторизованного клиента (та самая маскировка 403).
  • Если ресурс удалён навсегда и сервер об этом знает — спецификация рекомендует 410 Gone, но на практике чаще отдают 404.

Плюс нюанс: 404 — эвристически кэшируемый ответ, кэш может отдавать его повторно без обращения к серверу. Для собеседования достаточно сказать «ресурс не найден» и добавить, что иногда так маскируют 403.

Вопрос-ловушка: «а если ресурс когда-то был, но удалён?» По спецификации для этого есть 410 Gone — «знаем, что ресурс существовал, но его больше нет». Многие API продолжают отдавать 404, чтобы клиент не догадался о существовании объекта. На собеседовании достаточно упомянуть оба кода и объяснить, зачем серверу скрывать ресурс: это защита от перебора адресов и утечки информации о чужих данных.

500 Internal Server Error: «сервер не справился»

По RFC 9110, 500 означает, что сервер столкнулся с непредвиденным условием и не смог выполнить запрос. Это «дженерик»: сервер не нашёл более подходящий код из класса 5xx.

Что важно:

  • 500 — всегда ошибка серверной стороны: клиент прислал корректный запрос, но сервер упал.
  • Стоит знать соседей по классу: 502 Bad Gateway — промежуточный сервер получил невалидный ответ, 503 Service Unavailable — сервер временно недоступен, 504 Gateway Timeout — истекло время ожидания вышестоящего сервера.
  • В отличие от 401 и 403, клиент не может исправить 500: остаётся показать пользователю понятное сообщение и дать возможность повторить.

Ошибка-классика: «500 — это когда клиент отправил неверные данные». Нет: неверные данные — это 400 или 422. 500 — корректный запрос, который сервер не смог обработать из-за своей внутренней ошибки.

Обработка статусов в Android

После теории интервьюер почти всегда спрашивает практику: «а как вы обрабатываете ошибки в приложении?». Ответ строится на различии типов: IOException — проблемы сети, HttpException — ответ сервера с кодом ошибки.

NotesViewModel.kt
private fun messageFor(e: Exception): String = when (e) {
    is HttpException -> when (e.code()) {
        401 -> "Требуется вход в аккаунт"
        403 -> "Нет прав для этого действия"
        404 -> "Данные не найдены"
        500 -> "Сервер не смог обработать запрос"
        else -> "Ошибка сервера: ${e.code()}"
    }
    is IOException -> "Нет соединения с сервером"
    else -> "Неизвестная ошибка"
}

Чтобы получить код статуса, возвращайте Response<T> из Retrofit или ловите HttpException в catch — у него есть метод code(). Маппинг кода в сообщение и UI-состояние живёт в ViewModel, а не в Activity.

Если нужен не только код, но и тело ошибки — возвращайте Response<T> и читайте errorBody(): сервер часто кладёт в него человекочитаемое описание проблемы. Отдельный сценарий — 401 с протухшим токеном: в приложениях с refresh-токеном его обновляют в фоне и повторяют исходный запрос, без refresh-токена — отправляют на экран входа. Умение рассказать этот сценарий отличает ответ «знаю коды» от ответа «работал с реальным API».

  • Классы: 2xx — успех, 3xx — редирект, 4xx — ошибка клиента, 5xx — ошибка сервера.
  • 401 — «не аутентифицирован»: нужны валидные учётные данные, обязателен заголовок WWW-Authenticate.
  • 403 — «нет прав»: сервер знает клиента, но отказывает; повторять запрос бессмысленно.
  • 404 — «не найдено»: ресурса нет или он скрыт; иногда маскирует 403.
  • 500 — «сервер не справился»: непредвиденная внутренняя ошибка серверной стороны.
  • В Android: IOException — сеть, HttpException — код статуса; маппинг в UI-состояние — в ViewModel.

Нужна помощь в переходе на middle?

Бесплатная диагностика: разберу ваши пробелы в сети, HTTP и архитектуре и составлю план роста за 30–40 минут. Без обязательств — если менторство вам не подойдёт, честно скажу.

Итоги

HTTP-статусы — простая тема, на которой проверяют внимание к деталям. Четыре кода из заголовка закрывают половину вопросов:

  • 401 — «кто вы?» (аутентификация), 403 — «не пущу» (авторизация).
  • 404 — «не найдено или скрыто», 500 — «сервер не справился».
  • В Android: IOException против HttpException, маппинг кода в состояние UI.

Главное, что нужно запомнить

Один код — одна фраза: 401 — «нужны валидные учётные данные», 403 — «прав недостаточно», 404 — «ресурса нет или он скрыт», 500 — «внутренняя ошибка сервера». Отвечаете на эти четыре — вопрос про статусы закрыт.

Если сомневаетесь, как отвечать на сетевые вопросы в целом, — не нужно зубрить десять статей подряд. Напишите в Telegram, разберём вашу ситуацию и составим план подготовки.