Android中如何从Retrofit的Authenticator中获取服务端返回的错误响应体
可行实现方案
核心原理
OkHttp 提供的peekBody()方法可以拷贝一份Response Body流,读取拷贝后的流不会影响原Response的后续使用,完美解决Authenticator中读取错误信息后原请求Body为空的问题。
具体实现步骤
1. 安全读取错误响应
通过peekBody(Long.MAX_VALUE)获取完整的响应体拷贝,再解析为后端约定的错误结构:
// 读取拷贝后的响应体,不消耗原Response的Body val errorBody = response.peekBody(Long.MAX_VALUE).string() // 解析为你项目约定的错误实体类,示例用Gson解析 val errorInfo = Gson().fromJson(errorBody, ApiError::class.java)
ApiError为项目自定义的后端错误响应对应实体类,通常包含错误码、错误信息等字段。
2. 完整Authenticator代码示例
class TokenAuthenticator : Authenticator { // 约定的后端错误码 private val TOKEN_EXPIRED = 10001 private val NEED_RELOGIN = 10002 private val MAX_RETRY_COUNT = 2 override fun authenticate(route: Route?, response: Response): Request? { // 防止无限重试 if (response.responseCount >= MAX_RETRY_COUNT) { return null } // 读取错误信息 val errorBody = try { response.peekBody(Long.MAX_VALUE).string() } catch (e: Exception) { // 读取失败直接不处理 return null } val errorInfo = try { Gson().fromJson(errorBody, ApiError::class.java) } catch (e: Exception) { // 解析失败直接不处理 return null } return when (errorInfo.code) { // Access Token过期,执行同步刷新逻辑 TOKEN_EXPIRED -> { val newToken = syncRefreshToken() if (newToken.isNullOrEmpty()) { // 刷新失败,终止请求 null } else { // 携带新Token构建新请求返回,自动重试 response.request.newBuilder() .removeHeader("Authorization") .addHeader("Authorization", "Bearer $newToken") .build() } } // Refresh Token过期/账号异常,终止请求跳转登录 NEED_RELOGIN -> { // 可在此处发送全局事件通知页面跳登录 null } // 其他错误不处理 else -> null } } /** * 同步刷新Token的实现,注意不能用异步逻辑 */ private fun syncRefreshToken(): String? { // 此处实现你的同步刷新Token逻辑,比如直接用OkHttp调用刷新接口 return "new_access_token" } // 示例错误实体类 data class ApiError(val code: Int, val message: String) }
注意事项
- 不要直接调用
response.body?.string()读取响应,会消耗原流导致后续Retrofit拿到空Body - 刷新Token的逻辑必须为同步实现,Authenticator的
authenticate方法运行在后台线程,不支持异步回调 - 只有HTTP状态码为401的响应才会触发Authenticator,需确保后端Token过期时返回401状态码
内容的提问来源于stack exchange,提问作者user3863488
相关产品推荐
相关产品推荐

