You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 11:36:02