← Назад к вопросам

Может ли Retrofit помочь с просроченным токеном сделать запрос?

1.8 Middle🔥 141 комментариев
#Работа с данными#Сетевое взаимодействие

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Retrofit и обработка просроченных токенов

Да, Retrofit может помочь с обработкой запросов, использующих просроченные токены, но он не делает это автоматически. Retrofit — это библиотека для работы с HTTP-запросами, а управление жизненным циклом токенов (например, JWT) и их обновлением — это задача клиентской логики приложения. Однако Retrofit предоставляет мощные механизмы для реализации такой логики, главным образом через использование Interceptor.

Основной механизм: OkHttp Interceptor

Retrofit использует OkHttp под капотом для выполнения сетевых запросов. OkHttp позволяет добавлять Interceptor — промежуточные обработчики, которые могут модифицировать запросы перед отправкой и ответы после получения. Для работы с токенами наиболее полезен Authenticator или комбинация Interceptor и логики повторной попытки.

Пример реализации с Interceptor

Вот пример базовой реализации Interceptor, который проверяет ответ на просроченный токен (например, по статусу 401 Unauthorized) и пытается обновить токен, затем повторяет оригинальный запрос с новым токеном.

class TokenRefreshInterceptor(private val tokenManager: TokenManager) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        
        // Первая попытка с текущим (возможно, уже просроченным) токеном
        val response = chain.proceed(originalRequest)

        // Проверяем, если ответ 401 - токен просрочен
        if (response.code == 401) {
            // Синхронизируем блок, чтобы избежать множественных одновременных обновлений токена
            synchronized(this) {
                // Пытаемся получить новый токен (например, через запрос refresh)
                val newToken = tokenManager.refreshToken() // Этот метод должен выполнить сетевой запрос для обновления
                
                if (newToken != null) {
                    // Создаем новый запрос с обновленным токеном
                    val newRequest = originalRequest.newBuilder()
                        .header("Authorization", "Bearer $newToken")
                        .build()
                    
                    // Закрываем старый ответ и пробуем запрос с новым токеном
                    response.close()
                    return chain.proceed(newRequest)
                } else {
                    // Обновление токена не удалось - возвращаем оригинальный ошибку 401
                    return response
                }
            }
        }
        
        return response
    }
}

Архитектурные подходы и детали реализации

  1. Где разместить логику обновления токена?
    *   Логику обновления токена (`refreshToken()`) лучше вынести в отдельный класс, например, **`TokenManager`**. Он должен хранить текущий токен, знать `refreshToken`, и выполнять запрос для его обновления.
    *   Важно: запрос для обновления токена (`/auth/refresh`) должен выполняться **без использования того же Interceptor**, чтобы избежать рекурсии. Для этого можно создать отдельный экземпляр Retrofit без этого Interceptor.

```kotlin
// Пример TokenManager
class TokenManager(private val apiService: AuthApiService, private val secureStorage: SecureStorage) {
    
    fun refreshToken(): String? {
        val refreshToken = secureStorage.getRefreshToken()
        val response = apiService.refreshToken(refreshToken).execute() // Используем отдельный сервис без основного Interceptor
        
        if (response.isSuccessful) {
            val newAccessToken = response.body()?.accessToken
            secureStorage.saveAccessToken(newAccessToken)
            return newAccessToken
        }
        return null
    }
}
```

2. Обработка множественных одновременных запросов

    *   Если несколько запросов одновременно получают `401`, нужно предотвратить множественные одновременные попытки обновления токена. Используйте `synchronized` блок или механизм **Mutex** в Kotlin, как показано выше.
    *   Альтернативно, можно установить флаг `isRefreshing` и пока токен обновляется, ставить остальные запросы в очередь.

  1. Использование Authenticator
    *   OkHttp предоставляет специальный интерфейс **`Authenticator`**, предназначенный именно для аутентификации. Он автоматически вызывается при получении `401` и должен вернуть новый запрос с обновленными credentials.

```kotlin
class TokenAuthenticator(private val tokenManager: TokenManager) : Authenticator {
    
    override fun authenticate(route: Route?, response: Response): Request? {
        if (responseCount(response) >= 2) {
            // Если уже было две попытки аутентификации, прекращаем
            return null
        }
        
        val newToken = tokenManager.refreshToken()
        return if (newToken != null) {
            response.request.newBuilder()
                .header("Authorization", "Bearer $newToken")
                .build()
        } else {
            null
        }
    }
    
    private fun responseCount(response: Response): Int {
        var count = 1
        var priorResponse = response.priorResponse
        while (priorResponse != null) {
            count++
            priorResponse = priorResponse.priorResponse
        }
        return count
    }
}
```

Ключевые моменты и лучшие практики

  • Retrofit не управляет токенами — это ваша ответственность.
  • Interceptor или Authenticator — это правильное место для реализации логики обновления.
  • Запрос для обновления токена (refresh) должен быть исключен из общего Interceptor, чтобы избежать зацикливания.
  • Обработка race condition — критически важна при множественных параллельных запросах.
  • Состояние сети — учитывайте, что попытка обновления токена может также завершиться сетевой ошибкой.
  • Повторные попытки — после успешного обновления токена, только оригинальный запрос должен быть повторен. Не нужно повторять все запросы, которые привели к 401.

Таким образом, Retrofit, в сочетании с правильно реализованным OkHttp Interceptor или Authenticator, предоставляет отличную инфраструктуру для автоматического обновления просроченных токенов и повторения запросов с новыми данными аутентификации, что значительно улучшает пользовательский опыт и надежность приложения.