Какая логика повторения запросов при статусах 401, 403 и методе PUT
Что проверяют
Понимаете ли вы, какие ошибки лечатся повтором, а какие нет, и что такое идемпотентность на практике. Следом почти всегда спрашивают, что делать, если за время обновления токена ушло пять параллельных запросов.
Как отвечать
Разделите случаи по причине ошибки:
- 401 Unauthorized: клиент не аутентифицирован, чаще всего истёк access-токен. Один раз обновляете токен через refresh и повторяете исходный запрос. Если refresh тоже вернул 401, повторов больше нет, пользователь уходит на логин. Запрос помечают флагом вроде
_retry, чтобы не зациклиться; - 403 Forbidden: сервер знает, кто вы, но прав нет. Повтор ничего не изменит, нужно показать сообщение или скрыть действие. Исключение: некоторые бэкенды отдают 403 при устаревшем CSRF-токене, тогда токен обновляют и повторяют запрос один раз;
- PUT: по RFC 9110 метод идемпотентный, повтор с тем же телом приводит ресурс в то же состояние. Поэтому PUT можно повторять при сетевом сбое, 502, 503, 504 и 429, в отличие от POST, где без заголовка
Idempotency-Keyлегко создать дубль.
Повторы делают с экспоненциальной задержкой и случайным разбросом (jitter), ограничивают двумя-тремя попытками и уважают заголовок Retry-After у 429 и 503.
Обновление токена для параллельных запросов делают через single-flight: первый 401 запускает refresh, остальные ждут тот же промис и повторяются после него. В axios это интерцептор ответа с общей переменной промиса. Если в проекте TanStack Query, помните, что он по умолчанию повторяет queries три раза, а мутации не повторяет. Повтор на 401 в опции retry стоит отключить и оставить интерцептору.
Где спотыкаются
Повторяют запрос на 403 или на любой 4xx. Это лишняя нагрузка и задержка перед неизбежной ошибкой.
Путают идемпотентность с одинаковым ответом. Повторный PUT может вернуть другой код, важно только то, что состояние ресурса не меняется. А от одновременной правки двумя пользователями спасает не повтор, а If-Match с ETag и ответ 412.
Каждый параллельный запрос запускает свой refresh. При ротации refresh-токенов второй вызов уже невалиден, и пользователя выбрасывает из системы.