You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Retrofit请求头添加Access Token并通过Refresh Token刷新?

Retrofit请求头自动添加Access Token并实现Refresh Token刷新方案

我之前一直被Retrofit请求中Access Token的自动注入以及过期后用Refresh Token刷新的问题困扰,试了不少方法后,终于整理出一套对我来说最简单有效的实现方案,分享给有同样需求的开发者。

核心思路

通过OkHttp拦截器统一处理请求头的Token注入,同时在请求因Token过期失败时,自动调用刷新接口获取新的Access Token,并重试原请求。

具体实现

1. 定义Token管理类

先写一个单例类来全局统一管理Access Token和Refresh Token的存储与获取:

object TokenManager {
    private var accessToken: String? = null
    private var refreshToken: String? = null

    fun setTokens(access: String, refresh: String) {
        accessToken = access
        refreshToken = refresh
    }

    fun getAccessToken(): String? = accessToken
    fun getRefreshToken(): String? = refreshToken
}

2. 实现Token注入拦截器

创建OkHttp拦截器,在每个请求头中自动添加Access Token:

class TokenInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val token = TokenManager.getAccessToken()

        val authenticatedRequest = token?.let {
            originalRequest.newBuilder()
                .header("Authorization", "Bearer $it")
                .build()
        } ?: originalRequest

        return chain.proceed(authenticatedRequest)
    }
}

3. 实现Token刷新与重试拦截器

这个拦截器负责检测请求是否因Token过期失败,若失败则触发Token刷新并重试原请求:

class RefreshTokenInterceptor(private val retrofit: Retrofit) : Interceptor {
    @Synchronized
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)

        // 假设后端返回401状态码表示Token过期,可根据实际情况调整
        if (response.code == 401) {
            response.close()
            val newToken = refreshAccessToken() ?: return response

            // 用新的Access Token重新构建请求并重试
            val newRequest = request.newBuilder()
                .header("Authorization", "Bearer $newToken")
                .build()
            return chain.proceed(newRequest)
        }
        return response
    }

    private fun refreshAccessToken(): String? {
        val refreshToken = TokenManager.getRefreshToken() ?: return null
        return try {
            val apiService = retrofit.create(AuthApi::class.java)
            val response = apiService.refreshToken(refreshToken).execute()
            if (response.isSuccessful) {
                val newTokens = response.body() ?: return null
                TokenManager.setTokens(newTokens.accessToken, newTokens.refreshToken)
                newTokens.accessToken
            } else {
                null
            }
        } catch (e: Exception) {
            null
        }
    }
}

4. 配置Retrofit客户端

将两个拦截器添加到OkHttp客户端,注意拦截器的顺序:

// 先创建基础Retrofit实例(用于刷新Token的接口调用)
val baseRetrofit = Retrofit.Builder()
    .baseUrl("https://your-api-domain.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

// 配置OkHttp客户端,添加拦截器
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(TokenInterceptor())
    .addInterceptor(RefreshTokenInterceptor(baseRetrofit))
    .build()

// 最终的Retrofit实例
val retrofit = Retrofit.Builder()
    .baseUrl("https://your-api-domain.com/")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

注意事项

  • 确保刷新Token的接口不需要携带Access Token,或有独立的认证逻辑
  • 用@Synchronized修饰拦截方法是为了避免并发请求时多次重复刷新Token,也可根据需求用其他线程安全方案替代
  • 需根据后端实际返回的错误标识调整Token过期的判断逻辑,不一定是401状态码

这个方案逻辑清晰、代码量小,能覆盖大部分场景下的Token自动注入与刷新需求,对我来说是最省心的实现方式。

内容的提问来源于stack exchange,提问作者Farshad Molazeinali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:39:50