Kotlin开发Android应用收到Retrofit2 HTTP异常(404/500)后崩溃如何解决
问题原因
你遇到的崩溃是Retrofit协程扩展的默认行为导致的:新版Retrofit内置的await()扩展,只要收到HTTP响应码不在[200,300)区间,就会主动抛出HttpException。你当前的错误拦截器仅打印了日志,仍然将原始响应返回给Retrofit,所以异常依然会向上抛出,上层未捕获就会触发崩溃。
解决方案1:在拦截器中处理错误(符合你的需求)
你可以在拦截器检测到错误码后,直接构造一个200成功的自定义响应返回给Retrofit,同时把错误信息写入响应体,这样Retrofit就不会抛出异常:
override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() return try { val response = chain.proceed(request) when (response.code) { 403, 404, 500 -> { // 打印错误日志 Log.d("HttpError", "错误码${response.code}, 接口:${request.url}") // 构造自定义错误响应体,格式可以和后端约定,比如统一返回{"code":xxx,"msg":"xxx","data":null} val errorBody = ResponseBody.create( "application/json; charset=utf-8".toMediaType(), """{"code":${response.code},"msg":"请求错误","data":null}""" ) // 构造200成功响应返回,避免Retrofit抛异常 response.newBuilder() .code(200) .body(errorBody) .build() } else -> response } } catch (e: IOException) { // 处理无网络、请求超时这类IO异常,同样构造成功响应返回 val errorBody = ResponseBody.create( "application/json; charset=utf-8".toMediaType(), """{"code":-1,"msg":"网络异常","data":null}""" ) Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("OK") .body(errorBody) .build() } }
注意事项:你现在把errorsInterceptor放在拦截器队列最后是正确的,要放在AuthInterceptor、日志拦截器之后,才能正确拿到处理完成的响应。
解决方案2:更推荐的上层封装(耦合度更低)
如果不想在拦截器里篡改原始响应,也可以直接封装Retrofit的请求调用,统一捕获异常:
// 统一请求封装函数 suspend fun <T> safeApiCall(call: suspend () -> Response<T>): Result<T> { return try { val response = call() if (response.isSuccessful) { Result.success(response.body()!!) } else { Result.failure(HttpException(response)) } } catch (e: Exception) { Result.failure(e) } } // 调用示例 val result = safeApiCall { apiService.getUserInfo() } result.onSuccess { // 处理成功逻辑 }.onFailure { // 统一处理错误,弹提示、埋点等,不会触发崩溃 when(it) { is HttpException -> when(it.code()) { 404 -> Toast.makeText(context,"资源不存在",Toast.LENGTH_SHORT).show() 500 -> Toast.makeText(context,"服务器错误",Toast.LENGTH_SHORT).show() } else -> Toast.makeText(context,"网络异常",Toast.LENGTH_SHORT).show() } }
该方案不需要修改拦截器,也不会篡改原始响应,可维护性更高。如果你有其他业务逻辑需要用到真实的HTTP响应码,优先选择此方案。
内容的提问来源于stack exchange,提问作者Aden Kurmanov
相关产品推荐
相关产品推荐

