Retrofit为何修改NewsAPI响应?如何获取原始响应?
Retrofit返回401但看不到NewsAPI原始错误信息?解决方案来了
嘿,这个问题我之前对接NewsAPI的时候也遇到过,咱们先搞清楚原因,再一步步解决:
为什么Retrofit看起来“修改”了服务器响应?
其实Retrofit没有修改服务器的原始响应,你看到的Response{code=401, message=Unauthorized}只是HTTP协议层面的状态信息——因为NewsAPI对于apiKey无效或缺失的情况,都会返回401 Unauthorized的HTTP状态码,而Retrofit默认的Response对象展示的就是这个状态码对应的标准消息,不会自动把服务器返回的自定义错误JSON(就是你提到的{"status":"error","code":"apiKeyInvalid"...})放到Response的message字段里。
服务器返回的错误详情其实都在**响应体(ResponseBody)**里,只是需要你手动去提取解析。
如何获取原始响应或错误消息?
这里分两种场景,你可以根据需求选择:
1. 直接获取原始错误响应字符串
当response.isSuccessful()返回false时,调用response.errorBody()就能拿到错误响应体,再通过.string()方法转换成字符串:
// Kotlin + Retrofit 示例 newsApiService.getSources(apiKey).enqueue(object : Callback<SourceResponse> { override fun onResponse(call: Call<SourceResponse>, response: Response<SourceResponse>) { if (response.isSuccessful) { // 处理正常返回的数据源列表 } else { // 提取原始错误响应内容 val rawError = response.errorBody()?.string() Log.d("NewsAPI Debug", "Raw error response: $rawError") // 这里就能看到服务器返回的完整错误JSON了 } } override fun onFailure(call: Call<SourceResponse>, t: Throwable) { // 处理网络超时、无网络等非HTTP错误 } })
2. 解析成错误模型类(更优雅)
如果要结构化处理错误信息,可以先定义一个和NewsAPI错误响应匹配的数据类:
data class NewsApiError( val status: String, val code: String, val message: String )
然后用Gson/Moshi等序列化库把errorBody解析成这个模型类:
// 用Gson解析的示例 else { response.errorBody()?.let { errorBody -> val gson = Gson() val apiError = gson.fromJson(errorBody.charStream(), NewsApiError::class.java) // 现在可以直接用apiError.code和apiError.message做逻辑判断 when(apiError.code) { "apiKeyInvalid" -> showToast("API密钥无效,请检查") "apiKeyMissing" -> showToast("缺少API密钥,请补充") else -> showToast("请求失败:${apiError.message}") } } }
注意事项
errorBody()的流是一次性的,调用.string()后就不能再重复调用了,所以如果需要多次使用,记得先把字符串存到变量里。- 如果你用的是Retrofit的Coroutines suspend函数,处理逻辑是一样的:拿到Response对象后,判断
isSuccessful,失败时处理errorBody。
内容的提问来源于Stack Exchange,提问作者Tarun Trikha
相关产品推荐
相关产品推荐

