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

如何在组件中暴露模块提供的命名属性?拦截器动态设置access_token

解决动态更新Retrofit拦截器中access_token的问题

嗨,这个场景我太熟悉了!核心就是要让你的授权拦截器能动态获取最新的access_token,而不是在初始化时就固定死配置。给你分享两个最实用的实现方案:

方案一:用可更新的Token持有者(推荐)

这个方法最简单直接,不需要重新创建Retrofit或OkHttpClient实例,拦截器每次请求时都会主动获取最新的token。

步骤1:创建Token持有者类

先写一个用来存储和更新token的类,注意线程安全(避免多线程下token更新不及时的问题):

class TokenHolder {
    // 用@Volatile保证多线程下的可见性
    @Volatile
    var accessToken: String? = null
}

或者用AtomicReference实现更严谨的线程安全:

class TokenHolder {
    private val tokenRef = AtomicReference<String?>()

    fun updateToken(newToken: String?) {
        tokenRef.set(newToken)
    }

    fun getCurrentToken(): String? {
        return tokenRef.get()
    }
}

步骤2:在NetworkModule中注入TokenHolder和拦截器

让拦截器依赖这个TokenHolder,每次拦截请求时从holder中拿最新的token:

@Provides
@Singleton
fun provideTokenHolder(): TokenHolder = TokenHolder()

@Provides
@Singleton
fun provideAuthInterceptor(tokenHolder: TokenHolder): Interceptor {
    return Interceptor { chain ->
        val requestBuilder = chain.request().newBuilder()
        // 只有当token存在时才添加请求头
        tokenHolder.getCurrentToken()?.let { token ->
            requestBuilder.addHeader("Authorization", "Bearer $token")
        }
        chain.proceed(requestBuilder.build())
    }
}

// 接着把这个拦截器添加到OkHttpClient中
@Provides
@Singleton
fun provideOkHttpClient(authInterceptor: Interceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(authInterceptor)
        // 其他配置(比如超时、日志拦截器等)
        .build()
}

步骤3:获取到access_token后更新TokenHolder

当用户登录成功拿到access_token时,直接更新TokenHolder里的值就行:

// 比如登录接口回调中
tokenHolder.updateToken("your_new_access_token")

之后所有的请求都会自动带上最新的Authorization头了。

方案二:用复合拦截器动态替换授权逻辑

如果你的场景需要完全替换拦截器(而不是仅仅更新token),可以用一个复合拦截器来包装授权逻辑,动态添加或移除授权拦截器。

步骤1:创建复合授权拦截器

class CompositeAuthInterceptor : Interceptor {
    private val authInterceptor = AtomicReference<Interceptor?>(null)

    // 动态设置授权拦截器
    fun setAuthInterceptor(interceptor: Interceptor?) {
        authInterceptor.set(interceptor)
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        // 如果有授权拦截器就执行,否则直接放行请求
        return authInterceptor.get()?.intercept(chain) ?: chain.proceed(chain.request())
    }
}

步骤2:在NetworkModule中配置复合拦截器

@Provides
@Singleton
fun provideCompositeAuthInterceptor(): CompositeAuthInterceptor = CompositeAuthInterceptor()

@Provides
@Singleton
fun provideOkHttpClient(compositeAuthInterceptor: CompositeAuthInterceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(compositeAuthInterceptor)
        // 其他配置
        .build()
}

步骤3:拿到token后设置授权拦截器

// 登录成功后,创建带token的授权拦截器并设置进去
val authInterceptor = Interceptor { chain ->
    chain.proceed(
        chain.request().newBuilder()
            .addHeader("Authorization", "Bearer $accessToken")
            .build()
    )
}
compositeAuthInterceptor.setAuthInterceptor(authInterceptor)

总结

方案一的代码更简洁,性能也更好(不需要额外的对象切换),是大多数场景的首选。方案二更灵活,适合需要动态替换整个拦截逻辑的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:14:54