我刚刚遇到了同样的错误:java.net.ProtocolException: Too many follow-up requests: 21。为了您的兴趣,我使用的是 Retrofit 2.5.0 和 OkHttp 3.14.1,尽管版本并不重要。
我也只有在启用 Proguard 时才会出现此错误(实际上我使用的是 R8,但结果是一样的)。这很重要,并暗示了根本原因。
有什么问题?我使用 OAuth 进行身份验证,像往常一样添加“授权”标头。当令牌过期时,服务器会发送 401 Unauthorized。由于我使用 OkHttp Authenticator 来刷新令牌,所以当收到 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 失败,因此令牌不是神清气爽。结果是重复执行网络调用,直到抛出异常。
修复很简单。只需将@Keep 添加到ResponseError:
import androidx.annotation.Keep
@Keep
data class ResponseError(
val error: String? = null,
val error_description: String? = null
)
由于您的问题仅发生在启用 proguard 的情况下,因此请求或响应类可能被混淆,从而导致 JSON 解析失败。或者,您可能正在使用带有混淆类的 Gson.fromJson 和 Gson.fromJson 将一些 JSON 保存到共享首选项。
要解决此问题,请将@SerializedName 和/或@Keep 添加到您的所有请求和响应中(特别是枚举,这会带来更多麻烦)。或者,您可以简单地将所有请求和响应放入一个包和exclude it。除了请求和响应之外,还要特别注意任何Gson.fromJson 和Gson.fromJson 呼叫。
为了帮助诊断问题,您可以通过检查在app/build/outputs/mapping/release/mapping.txt 中找到的映射文件(对于发布版本)来检查 proguard/R8 的功能。它包含 proguard/R8 对您的代码所做的所有转换。
您还可以通过 Build -> Analyze APK... 分析 APK... 您会以非常简单的方式查看哪些类被混淆了。您可以同时分析 2 个 APK(一个已缩小,一个未缩小)并进行比较。