Контекст: При быстрых F5 (3-4 раза) на /places/my пользователя деавторизует — /auth/me начинает стабильно падать с 401.
Коренная причина: write-лимитер (burst=10) исчерпывается быстрее, чем refresh-механизм успевает восстановить сессию.
refreshSession() вызывает /auth/me без Bearer → 401fetchPlaces() вызывает /places/my без Bearer → 401request() → catch → refreshAccessToken() + ретрай с Bearer/auth/me с Bearer → 200 (write limiter: +1)/places/my с Bearer → 200 (write limiter: +1)Когда burst исчерпан:
/auth/me → 429 (Too Many Requests)request() в catch → деавторизацияrefreshSession — сначала refresh, потом /auth/mefrontend/src/hooks/useAuth.tsx:
// было:
const res = await api.get<User>('/auth/me')
// стало:
const newToken = await refreshAccessToken()
setAccessToken(newToken)
const res = await api.get<User>('/auth/me')
Теперь /auth/me приходит с Bearer с первого раза — ни 401, ни ретрая. Сокращает write-лимитер с 2 до 1 хита на page load.
refreshAccessToken из api.tsНужен для прямого вызова из refreshSession().
request()frontend/src/lib/api.ts:
if (res.status === 429 && !isRetry) {
await new Promise(r => setTimeout(r, 1000))
return request<T>(path, options, true)
}
backend/cmd/api/main.go (in-memory fallback): 10/60.0, 10 → 60/60.0, 60backend/internal/middleware/ratelimit_redis.go (Redis): Limit: 10 → Limit: 60Файлы:
frontend/src/hooks/useAuth.tsx:38-41frontend/src/lib/api.ts:19 (экспорт)frontend/src/lib/api.ts:72-75 (429 retry)backend/cmd/api/main.go:149backend/internal/middleware/ratelimit_redis.go:146#auth #rate-limiting #frontend #backend #bugfix