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

无法设置拦截器变量值:AppInterceptor的accessToken始终为null求助

问题:Interceptor中accessToken设置后仍为null的问题

调用setAccessToken(accessToken: String?)后,日志能正确打印令牌,但intercept函数中获取到的accessToken始终为null。相关代码如下:

AppInterceptor代码

@Singleton
class AppInterceptor @Inject constructor() : Interceptor {
    private var accessToken: String? = null
    fun setAccessToken(accessToken: String?) {
        this.accessToken = accessToken
        Log.d("Tag", "Access Setting: ${this.accessToken}")
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        val requestBuilder: Request.Builder = request.newBuilder()
        accessToken?.let { requestBuilder.addHeader("authorization", "Bearer $it") }

        return chain.proceed(requestBuilder.build())
    }
}

ViewModel中调用代码

@HiltViewModel
class ApiViewModel @Inject constructor(
    private val apiHelper: APIHelper,
    private val oktaManager: OktaManager,
    private val interceptor: AppInterceptor
) : AndroidViewModel() {

    fun getResult() {
        viewModelScope.launch(Dispatchers.IO) {
            interceptor.setAccessToken(oktaManager.gettingOktaToken())
            try {
                apiHelper.getResults()                   
            } catch (e: Exception) {
                Log.e("error", e.toString())
            }
        }
    }    
}

Retrofit构建器代码

@Module
@InstallIn(SingletonComponent::class)
object RetrofitBuilder {


    private const val BASE_URL = "https://myUrl"

    private val interceptor = run {
        val httpLoggingInterceptor = HttpLoggingInterceptor()
        httpLoggingInterceptor.apply {
            httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
        }
    }

    @Singleton
    @Provides
    fun provideOkHTTPClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .apply { addInterceptor(AppInterceptor()) }
            .addInterceptor(interceptor)
            .build()
    }

    @Singleton
    @Provides
    fun provideObjectMapper(): ObjectMapper {
        return jacksonObjectMapper().registerModule(JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
    }

    @Singleton
    @Provides
    fun provideRetrofitInstance(
        client: OkHttpClient,
        objectMapper: ObjectMapper
    ): Retrofit {
        return Retrofit.Builder()
            .client(client)
            .baseUrl(BASE_URL)
            .addConverterFactory(JacksonConverterFactory.create(objectMapper))
            .build()
    }

    @Singleton
    @Provides
    fun provideApiService(retrofit: Retrofit): IApiService {
        return retrofit.create(IApiService::class.java)
    }
}

问题原因

核心问题是存在两个独立的AppInterceptor实例:

  • 一个是Hilt根据@Singleton注解注入到ViewModel中的单例实例
  • 另一个是在provideOkHTTPClient方法中通过new AppInterceptor()手动创建的全新实例

ViewModel中调用setAccessToken修改的是第一个实例的token,但OkHttpClient实际使用的是第二个未被赋值的实例,因此intercept中拿到的始终是null。

解决方案

修改RetrofitBuilder模块,通过Hilt注入AppInterceptor单例实例,而非手动创建:

@Singleton
@Provides
fun provideOkHTTPClient(appInterceptor: AppInterceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(interceptor)
        .addInterceptor(appInterceptor) // 使用Hilt注入的单例实例
        .addInterceptor(interceptor)
        .build()
}

额外优化建议

  1. 避免重复添加日志拦截器:当前代码中前后两次添加了同一个HttpLoggingInterceptor,可简化为一次:
@Singleton
@Provides
fun provideOkHTTPClient(appInterceptor: AppInterceptor): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(interceptor)
        .addInterceptor(appInterceptor)
        .build()
}
  1. 线程安全优化:由于setAccessToken可能在主线程调用,intercept在IO线程执行,建议用AtomicReference保证线程安全:
@Singleton
class AppInterceptor @Inject constructor() : Interceptor {
    private val accessToken = AtomicReference<String?>()
    
    fun setAccessToken(accessToken: String?) {
        this.accessToken.set(accessToken)
        Log.d("Tag", "Access Setting: ${this.accessToken.get()}")
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        val requestBuilder: Request.Builder = request.newBuilder()
        accessToken.get()?.let { requestBuilder.addHeader("authorization", "Bearer $it") }

        return chain.proceed(requestBuilder.build())
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:45:34