Ошибки 401, 403 и 404: как искать причину
Три самые частые ошибки в заявках выглядят одинаково: у пользователя что-то не открылось. Но останавливается запрос в разных местах, и проверять в каждом случае нужно своё. Разберём, как по коду ответа сразу сузить круг поиска.
Что общего у этих трёх кодов
Все три относятся к группе 4xx. По стандарту это ошибки клиента: предполагается, что сервер получил некорректный запрос и сам исправен. Вывод «виноват пользователь» делать при этом рано — коды 4xx регулярно возникают из-за настроек самого сервиса, и добрая половина заявок именно такая.
Важнее другое свойство. Код ответа сообщает не причину, а стадию, на которой запрос остановился. Этого достаточно, чтобы отсечь половину гипотез до того, как вы откроете логи.
401 — сервис не понял, кто вы. 403 — понял, но не даёт. 404 — того, что вы просите, у него нет.
401 Unauthorized: сервис не знает, кто вы
Название вводит в заблуждение: несмотря на слово «unauthorized», код относится к аутентификации, а вопрос прав решается кодом 403.
В подавляющем большинстве заявок причина одна из двух: токен истёк либо заголовок с ним вообще не дошёл до сервиса. С них и начинайте.
Что проверять
- Заголовок
Authorizationесть в запросе? Он мог не отправиться: клиент не подставил токен, прокси вырезал заголовок, запрос ушёл без авторизации после редиректа. - Не истёк ли токен. У JWT срок жизни лежит в поле
exp. Сравните его с текущим временем — часто оказывается, что токен протух несколько часов назад, а клиент не обновил его через refresh. - Тот ли контур. Токен, выданный на тестовом стенде, на проде не примут. Проверьте, к какому окружению обращается клиент.
- Формат и целостность: схема
Bearerс пробелом перед значением, отсутствие лишних кавычек, не обрезан ли токен при копировании. Длинные токены обрываются на переносе строки регулярно. - Расхождение часов на клиенте или сервере — тогда токен считается ещё не наступившим или уже истёкшим.
- Сессия завершена принудительно: смена пароля, выход на другом устройстве, разлогин при деплое.
Быстрая проверка — повторить запрос командой curl -i и посмотреть заголовки ответа. Корректно настроенный сервис вместе с 401 отдаёт заголовок WWW-Authenticate, который подсказывает ожидаемый способ аутентификации.
403 Forbidden: сервис знает, кто вы, и отказывает
Здесь личность установлена, запрос отклонён осознанно. Это самый неоднозначный код из трёх, потому что за ним стоят два совершенно разных класса причин — и чинят их разные люди.
Права внутри приложения
- У пользователя нет нужной роли или он не состоит в нужной группе.
- Прав на конкретный объект нет: доступ к чужому заказу, чужому проекту, чужой организации.
- Учётная запись заблокирована или не подтверждена.
- Истёк оплаченный период, лицензия, доступ к платному разделу.
Ограничения инфраструктуры
- Ограничение по IP. Раздел доступен только из офисной сети или через VPN. Классика: у пользователя отвалился VPN, а он этого не заметил.
- WAF. Запрос показался межсетевому экрану подозрительным — например, из-за спецсимволов в параметрах или нестандартного User-Agent.
- Геоблокировка либо проверка заголовка
RefererилиOrigin. - Настройки веб-сервера: в nginx 403 возвращается, если запрошен каталог, в нём нет индексного файла, а автоматический листинг выключен. Второй вариант — у процесса веб-сервера нет прав на чтение файла на диске.
Как понять, какая это группа
Смотрите, что именно пришло в ответе. Приложение отвечает в своём обычном формате — как правило, JSON с полем об ошибке. Если вместо этого вы видите стандартную HTML-страницу nginx или страницу блокировки защитного экрана, запрос до приложения просто не дошёл, и разбираться в ролях пользователя бессмысленно.
От этого зависит и то, кому уходит задача. Перепутав аутентификацию с правами, вы отправите разбираться разработчиков там, где нужны были администраторы сети, и потеряете день на переброске тикета.
Есть и отдельная ловушка. Часть API возвращает 403 при полном отсутствии токена — там, где по стандарту полагается 401. Поэтому не делайте вывод по одному коду: читайте тело ответа, настоящая причина обычно указана там.
404 Not Found: ресурса не существует
Самое частое объяснение — опечатка в адресе, и иногда так и есть. Но закрывать заявку на этом основании не стоит: у 404 хватает причин, не связанных с пользователем вовсе.
Запрос мог попасть не на тот виртуальный хост, если на сервере живёт несколько сайтов и заголовок Host пришёл неправильный. Правило маршрутизации на балансировщике могло не совпасть после релиза, когда путь у сервиса изменился, а конфигурацию не обновили. Одностраничные приложения без резервного маршрута отдают 404 при прямом открытии внутреннего адреса, хотя по ссылкам внутри сайта всё работает. Наконец, часть API намеренно отвечает 404 вместо 403, чтобы не раскрывать посторонним сам факт существования объекта.
Отдельно различайте два разных 404: когда не найден адрес и когда адрес существует, но приложение не нашло конкретный объект. Код одинаковый, но во втором случае в теле будет осмысленное сообщение, и это уже вопрос к данным.
Как понять, кто именно ответил
Главный вопрос при разборе любого кода 4xx — дошёл ли запрос до приложения. Три способа ответить:
- Логи веб-сервера. В access-логе nginx видно строку с адресом, статусом и временем обработки. Отфильтруйте по нужному статусу и времени.
- Логи приложения. Если запроса там нет, а в access-логе он есть — отвечал прокси, балансировщик или защитный экран.
- Тело и заголовки ответа. Заголовок
Serverподсказывает, кто сформировал ответ.
Порядок разбора заявки
1. Зафиксируйте точный адрес, метод запроса, время с указанием часового пояса и идентификатор пользователя. Без этих четырёх вещей двигаться дальше нельзя, и задача на разработку с текстом «не работает, ошибка 403» вернётся к вам в тот же день. 2. Проверьте, у скольких пользователей воспроизводится. Если один и тот же код пошёл массово, это уже не работа с заявкой, а инцидент, и порядок действий другой. 3. Попробуйте воспроизвести сами. Воспроизводится у всех — ищите в конфигурации. Только у одного — ищите в его правах и данных. 4. Сравните с пользователем, у которого всё работает. Разница между двумя запросами обычно и есть причина. 5. Найдите запрос в логах по времени и статусу, определите, кто сформировал ответ. 6. Только после этого заводите задачу на разработку — с готовым curl и ссылкой на логи.
