Семантика HTTP
HTTP-коды и методы это контракт, по которому клиент решает: ретраить или нет, идти логиниться или это бесполезно, битый у него запрос или недопустимое значение. Собес гоняет по границам, которые все путают: 401 против 403, 400 против 422, PUT против PATCH - потому что ошибка тут даёт реальные баги в интеграциях.
Типовые формулировки: «чем 401 отличается от 403?», «PUT или PATCH?», «какой код на невалидное значение поля».
Методы, идемпотентность и ретраи
GET - безопасное чтение, POST - создать или выполнить действие, PUT - заменить целиком, DELETE - удалить. GET и HEAD безопасны - не меняют состояние. Ключевое свойство для ретраев - идемпотентность: PUT и DELETE идемпотентны (повтор даёт то же состояние), POST - нет: два POST /orders создадут два заказа.
Отсюда практика: ретраить сетевой сбой безопасно для GET/PUT/DELETE, а для POST - только с защитой от задвоения (см. Idempotency-Key). PUT заменяет ресурс ЦЕЛИКОМ, поэтому неполное тело затрёт непереданные поля; PATCH меняет только указанные и идемпотентен не гарантированно.
// Классы кодов: 2xx успех, 4xx вина клиента, 5xx сбой сервера - по ним понимают, кто виноват и стоит ли повторять.
- идемпотентность
- повтор запроса не меняет итог против одного вызова
- PUT vs PATCH
- полная замена против частичного обновления
Коды-двойники: 401/403 и 400/422
401 и 403 - разные вещи. 401 - не аутентифицирован: токена нет или он просрочен, клиент должен пойти обновить токен и повторить. 403 - аутентифицирован, но прав нет: логиниться заново бесполезно, ответ не изменится. Путаница ломает клиентскую логику: по 401 клиент рефрешит токен, по 403 - не должен.
400 и 422 тоже про разное. 400 - запрос синтаксически битый (невалидный JSON, кривой формат). А валидный JSON с недопустимым значением, скажем age=-5, точнее описывает 422 Unprocessable Entity - его и отдают FastAPI и DRF (Django REST Framework) при ошибке валидации схемы.
// Отдавать 200 с телом ошибки вместо 4xx - маскировать проблему: клиент считает запрос успешным.
- 401 vs 403
- не аутентифицирован против нет прав
- 400 vs 422
- битый синтаксис против валидного, но недопустимого
Как отвечать: «Чем 401 отличается от 403?»
401 это про аутентификацию: сервер не знает, кто ты, потому что токена нет или он просрочен. Клиент на 401 должен пойти получить или обновить токен и повторить запрос. 403 - про авторизацию: личность установлена, но конкретно этих прав у тебя нет - например, обычный юзер лезет в админский эндпоинт. Повторять логин тут бессмысленно, ответ не изменится, пока не выдадут права. Практический смысл в том, что клиентская логика на них реагирует по-разному: 401 запускает рефреш токена, а 403 это стоп, показать «нет доступа».
Разведены аутентификация и авторизация с конкретной реакцией клиента на каждый код - видно, что человек понимает последствия для интеграции, а не только определения.
На чём валят
- −PUT неполным телом затрёт непереданные поля - он заменяет ресурс целиком; для частичного нужен PATCH.
- −Отдавать 200 с телом ошибки вместо 4xx - маскировка проблемы от клиента и прокси.
- −Путать 401 и 403: клиент по 401 обновит токен, а по 403 это бессмысленно.
- −Слать 400 на валидный JSON с недопустимым значением - точнее 422; и наоборот.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.
- Что означают классы кодов 2xx, 4xx и 5xx?A)Информация, редирект и успех — по возрастанию номера классаB)Кэшируемый, некэшируемый и потоковый ответ соответственноC)Все три — разновидности успешного ответа с разным теломD)Успех, ошибка клиента и ошибка сервера соответственно
показать ответ и разбор
+D)Успех, ошибка клиента и ошибка сервера соответственно// разбор: 2xx — успех (200 OK, 201 Created, 204 No Content), 4xx — ошибка на стороне клиента (400 плохой запрос, 404 не найдено, 401/403 доступ), 5xx — сбой на сервере (500, 502, 503). Разделение 4xx/5xx важно: по нему понимают, кто виноват и стоит ли ретраить.
- Чем PUT отличается от POST по идемпотентности?A)PUT идемпотентен: повтор даёт то же состояние; POST — нетB)Оба идемпотентны, поэтому их можно повторять сколько угодноC)POST идемпотентен, а PUT при повторе создаёт дубликаты ресурсаD)Идемпотентность зависит только от базы, а не от самого метода
показать ответ и разбор
+A)PUT идемпотентен: повтор даёт то же состояние; POST — нет// разбор: PUT идемпотентен: повтор одного и того же PUT приводит ресурс к тому же состоянию (заменяет целиком). POST не идемпотентен — два POST /orders создадут два заказа. Отсюда практика: ретраи безопасны для PUT/DELETE/GET, а для POST нужен ключ идемпотентности.
- Когда вернуть 401, а когда 403?A)401 — сервер упал, 403 — ресурс временно недоступен клиентуB)401 — ресурс не найден, 403 — неверный формат тела запросаC)401 и 403 взаимозаменяемы, разница только в тексте сообщенияD)401 — не аутентифицирован, 403 — прав не хватает
показать ответ и разбор
+D)401 — не аутентифицирован, 403 — прав не хватает// разбор: 401 Unauthorized (по факту «не аутентифицирован») — личность не установлена: нет/просрочен токен. 403 Forbidden — личность известна, но прав на действие нет. Практическое следствие: на 401 клиент идёт логиниться/обновлять токен, на 403 — это бесполезно.
- Тело запроса — валидный JSON, но поле age = -5 (недопустимо). Какой код точнее?A)200 с телом ошибки, чтобы не пугать клиента кодом четвёртой сотниB)500, ведь сервер не смог обработать присланное значение поляC)400, потому что проблема входа — это Bad RequestD)422: синтаксис верен, но данные не проходят по смыслу
показать ответ и разбор
+D)422: синтаксис верен, но данные не проходят по смыслу// разбор: 400 Bad Request — про синтаксически битый запрос (не распарсился). Если JSON корректен, но нарушает правила (отрицательный возраст) — точнее 422 Unprocessable Entity; именно его FastAPI/DRF отдают на ошибки валидации. 5xx тут ни при чём — виноват клиент, не сервер.
- Чем PATCH отличается от PUT?A)PATCH работает лишь с коллекциями, а PUT — с элементамиB)Разницы нет, PATCH — просто новое имя для метода PUT сегодняC)PATCH меняет часть полей, PUT заменяет ресурс целикомD)PATCH только читает изменённые поля, а PUT их записывает
показать ответ и разбор
+C)PATCH меняет часть полей, PUT заменяет ресурс целиком// разбор: PUT заменяет ресурс целиком — не переданные поля обнулятся/сбросятся к дефолту. PATCH меняет только указанные поля, оставляя прочие как есть. PUT идемпотентен по определению; PATCH может быть идемпотентным или нет — зависит от формата патча.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.