协议异常:在Android中使用Proguard和OkHttp 3.0时,跟随请求过多:21

13

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

在调试模式下,将minifyEnabled设置为false时一切都正常工作,但是一旦我将minifyEnabled更改为true,就会出现以下异常:

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

以下是我针对 OkHttp 的 Proguard 规则:

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

我不明白为什么会抛出这个异常,也不知道为什么应用程序似乎要发出21个后续请求。有人可以帮帮我吗?

1个回答

6
我刚遇到了完全相同的错误:java.net.ProtocolException:Too many follow-up requests: 21。为了您的利益,我正在使用Retrofit 2.5.0和OkHttp 3.14.1,尽管版本不太重要。
我也只有在启用Proguard时才会出现此错误(实际上我正在使用R8,但结果是相同的)。这很重要,并提示了根本原因。
问题出在哪里?我使用OAuth进行身份验证,像往常一样添加“授权”头。当令牌过期时,服务器会发送401 Unauthorized响应。由于我正在使用一个OkHttpAuthenticator来刷新令牌,所以当收到401响应时,将调用 authenticate方法。
问题在于,我使用Gson解析401 Unauthorized请求的响应,如下所示:
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...
}

由于 ResponseError 类被 Proguard 混淆,导致其字段与服务器发送的 JSON 的名称不匹配,使得 Gson().fromJson 调用失败,结果导致令牌无法刷新。这样就会不停地进行网络调用,直到异常抛出。

解决方法很简单。只需在 ResponseError 上添加 @Keep 注释即可:

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。或者,您可以将所有请求和响应放入一个单独的包中,并将其排除。除了请求和响应之外,还要特别注意任何Gson.fromJsonGson.fromJson的调用。
为帮助诊断问题,您可以检查proguard/R8所做的工作,方法是检查您将在app/build/outputs/mapping/release/mapping.txt(针对发布版本)中找到的映射文件。它包含proguard/R8对您的代码所做的所有转换。
您还可以通过Build -> Analyze APK... 分析APK。您将以非常简单的方式看到哪些类正在被混淆。您可以同时分析2个APK(一个经过缩小,一个未经缩小)并进行比较。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接