ProtocolException:太多后续请求:21中包含Proguard和Android中的OkHttp 3.0

时间:2016-11-15 08:27:15

标签: android proguard retrofit2 android-proguard okhttp3

我正在使用Retrofit 2.1.0和OkHttp 3.4.2创建一个应用程序。

在minifyEnabled设置为false的调试模式下,一切正常,但只要我将minifyEnabled更改为true,我就会得到以下异常:

HTTP FAILED: java.net.ProtocolException: Too many follow-up requests: 21

我的Proguard OkHttp规则如下:

-keep class com.squareup.okhttp3.** {
    *;
}
-dontwarn okhttp3.**
-dontwarn okio.**

我无法理解为什么抛出这个异常,我不明白为什么该应用程序似乎正在制作21个跟进请求。任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

我刚刚遇到了完全相同的错误:java.net.ProtocolException: Too many follow-up requests: 21。为了您的利益,我使用Retrofit 2.5.0和OkHttp 3.14.1,尽管版本无关紧要。

我也仅在启用Proguard的情况下出现此错误(实际上,我使用的是R8,但结果是相同的)。这很重要,并暗示了根本原因。

出什么问题了?我使用OAuth进行身份验证,照常添加“ Authorization”标头。当令牌过期时,服务器将发送“ 401未经授权”。由于我使用OkHttp Authenticator刷新令牌,因此当收到401时,将调用authenticate方法。

问题是我使用Gson解析了401未经授权的请求的响应,如下所示:

override fun authenticate(route: Route?, response: Response): Request? {
    val responseError: ResponseError? = response.body()?.let {
        Gson().fromJson(it.string(), ResponseError::class.java) // <- Fails!
    }
    // Check server response and decide if should refresh token...
}

但是由于proguard对类ResponseError进行了混淆,因此其字段与服务器发送的JSON名称不匹配,这使得Gson().fromJson失败,因此令牌未刷新。结果是反复进行网络调用,直到引发异常为止。

修复很简单。只需将@Keep添加到ResponseError

import androidx.annotation.Keep

@Keep
data class ResponseError(
    val error: String? = null,
    val error_description: String? = null
)

由于您的问题仅在启用了proguard的情况下发生,因此可能混淆了请求或响应类,这使JSON解析失败。或者,您可能使用Gson.fromJsonGson.fromJson和一个混淆的类来将一些JSON保存到共享首选项。

要解决此问题,请将@SerializedName和/或@Keep添加到您的所有请求和响应中(特别是枚举,这会带来更多麻烦)。或者,您可以简单地将所有请求和响应放入单个包中,然后exclude it。除了请求和响应之外,还要特别注意任何Gson.fromJsonGson.fromJson调用。

要帮助诊断问题,您可以通过检查在app/build/outputs/mapping/release/mapping.txt中找到的映射文件(对于发行版)来检查proguard / R8的功能。它包含了proguard / R8对您的代码所做的所有转换。

您也可以通过执行Build->分析APK ...来分析APK。您将以非常简单的方式查看混淆了哪些类。您可以同时分析2个APK(一个缩小,一个未缩小)并进行比较。