Fix infinite reload loop on the login screen itself

apiFetch()'s fallback for a failed silent-refresh unconditionally does
window.location.href = "/" — but Auth.tsx (the "/" route) calls this same
apiFetch("/users/me") on mount just to check whether a session already
exists. For any fresh/anonymous visit that 401s (the normal, expected
case), the failed-refresh branch fired a navigation to "/" while already
sitting on "/" — which browsers still treat as a real reload, not a
no-op. That reload remounts the app, which repeats the exact same check,
which fails the exact same way: an infinite reload loop, observed live as
the page "loading forever" and — since the bot's WebApp bridge lands on
/profile and bounces to "/" on any auth hiccup — the "Личный Кабинет"
button appearing to do nothing.

Only redirect when not already on "/". Verified with a real headless
Chrome run (Playwright): before, this path can't be distinguished from a
one-shot failure without watching for repeated navigation; confirmed here
that with the guard in place the app performs exactly one GET /users/me +
one POST /auth/refresh and then sits idle, no repeat requests or
navigations over 12s of observation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 14:03:45 +07:00
parent 4a8816b908
commit 4f1efc6ff9
+10 -1
View File
@@ -35,6 +35,13 @@ function toRequestInit(options: RequestInit): RequestInit {
/// Единая обёртка над fetch для авторизованных запросов: всегда с cookie,
/// при первом 401 пробует silent-refresh и повторяет запрос один раз, при
/// провале — чистит сторону клиента и уводит на экран логина.
///
/// Редирект пропускается, если мы и так уже на `/` (экран логина): иначе
/// `window.location.href = "/"` там же, где мы уже находимся, всё равно
/// вызывает полную перезагрузку страницы — React-приложение перемонтируется,
/// Auth.tsx заново дёргает тот же `/users/me`, получает тот же 401 (для
/// анонимного визита это нормальное, ожидаемое состояние, а не сбой) — и
/// уходит в бесконечный цикл перезагрузок.
export async function apiFetch(
path: string,
options: RequestInit = {},
@@ -46,7 +53,9 @@ export async function apiFetch(
const refreshed = await refreshSession();
if (!refreshed) {
window.location.href = "/";
if (window.location.pathname !== "/") {
window.location.href = "/";
}
return res;
}