HttpLoggingInterceptor 干扰刷新令牌机制

Posted

技术标签:

【中文标题】HttpLoggingInterceptor 干扰刷新令牌机制【英文标题】:HttpLoggingInterceptor interfering with with refresh token mechanism 【发布时间】:2020-06-30 19:52:22 【问题描述】:

我在使用 OkHttp3 Interceptorandroid 应用程序中遇到了一个非常奇怪的问题,我为不同的构建变体设置了不同的日志记录级别。

我在我的应用程序中设置了一个OkHttp3Interceptor 来拦截API 请求,如果任何API 返回401 错误,拦截器从后端获取刷新的令牌并使用新令牌更新原始请求的标头并重复它。我们称之为 RefreshTokenInterceptor。我在构建我的OKHttpClient 时添加了这个拦截器。除此之外,我还添加了一个 HttpLoggingInterceptor 来记录 API 请求和响应,或者在发布版本的情况下停止记录。我们称之为 LoggingInterceptor

这是我构建OkHttpClient 的代码。这段代码应该足够了,因为如果日志级别发生变化,刷新机制可以正常工作。

val loggingInterceptor = HttpLoggingInterceptor()

// changing level to Level.BODY in the below solves the issue,
// but I don't want to log the results
when 
        BuildConfig.DEBUG -> loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
        else -> loggingInterceptor.level = HttpLoggingInterceptor.Level.NONE


val httpClientBuilder = OkHttpClient.Builder()
      .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
      .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS)
      .addInterceptor(ConnectivityInterceptor())
      .addInterceptor(TokenRefreshInterceptor())
      .addInterceptor(loggingInterceptor)
      .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)

当我在两种情况下都将 LoggingInterceptor 的日志记录级别设置为 Level.BODY 时,一切正常。但是如果日志级别设置为Level.NONE,令牌刷新机制就会停止工作。

更具体地说,在这种情况下,这就是 RefreshTokenInterceptor 中发生的情况:当请求返回 401 时,会进行刷新调用,但之后没有任何反应。没有成功或失败案例被调用(也许拦截器 Chain 中断但谁知道)。

这是我目前尝试过的

完全删除 LoggingInterceptor -> 不起作用 将所有构建变体的日志级别设置为Level.NONE -> 确实 不工作 将所有构建变体的日志记录级别设置为Level.BODY -> 有效 像魔术一样

我今天也对此进行了很多搜索,但找不到日志级别之间的任何链接,从而弄乱了其他拦截器。任何帮助将不胜感激,如果您需要更多代码,我可以发布它。

【问题讨论】:

您可以尝试在 TokenRefreshInterceptor 之前先添加 loggingInterceptor 吗?不确定,但它可能与请求/响应链接有关。另外,您可以发布您的 TokenRefreshInterceptor 代码吗? 实际上问题是由未关闭的 OkHttp3 Response 对象创建的 RefreshTokenInterceptor 中的内存泄漏引起的。当我关闭它时,问题就解决了。 【参考方案1】:

问题是由内存泄漏引起的,因为TokenRefreshInterceptor 中的OkHttp3 Response 对象没有被关闭。我在Firebase Console 上知道了这个泄漏。使用后关闭此Response 解决了该问题。但是我仍然不确定为什么当我启用正文级日志记录时它工作得很好。

【讨论】:

使用chain.proceed尝试下一个请求时,需要释放上一个响应体持有的资源。调用 close() 是最好和最安全的方法。读取整个正文也会释放这些资源,这就是拦截器阻止崩溃的原因。 哦,这完全有道理。非常感谢:)

以上是关于HttpLoggingInterceptor 干扰刷新令牌机制的主要内容,如果未能解决你的问题,请参考以下文章

Android Retrofit2 0 查看log和JSON字符串(HttpLoggingInterceptor)

Android Retrofit2.0 查看log和JSON字符串(HttpLoggingInterceptor)

Android HttpLoggingInterceptor的用法简介

无法在HttpLoggingInterceptor Retrofit2.0上解析setLevel

如何为 KTOR 添加日志拦截器?

http解析异常阿波罗Graphql