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

Retrofit+协程结合Gson实现自定义错误处理方案咨询

处理Retrofit Suspend函数的自定义错误响应

嘿,针对你用Retrofit 2.6.1+suspend函数的场景,我来一步步讲怎么处理这类自定义错误响应,顺便解答你关于Converters/TypeAdapters/Deserializers的疑问~

第一步:定义错误模型类

首先,先把API返回的错误响应转换成对应的Kotlin数据类,方便后续解析:

data class ApiError(
    val message: String,
    val error_code: String,
    val error_code_description: String,
    val correlation_id: String
)

第二步:解析HttpException中的错误响应

当API返回非2xx状态码时,Retrofit的suspend函数会自动抛出HttpException。我们可以从这个异常里提取响应体,用Gson解析成上面定义的ApiError。

写个工具函数来封装这个解析逻辑:

fun HttpException.parseApiError(): ApiError? {
    return try {
        response()?.errorBody()?.string()?.let { errorBodyString ->
            Gson().fromJson(errorBodyString, ApiError::class.java)
        }
    } catch (e: Exception) {
        null // 解析失败时返回null,你可以根据需求改成默认错误或者抛出异常
    }
}

第三步:在API调用中捕获并处理错误

现在你调用login接口时,用try-catch捕获异常,就能拿到自定义的错误信息了:

try {
    val user = service.login()
    // 处理登录成功的业务逻辑
} catch (e: HttpException) {
    val apiError = e.parseApiError()
    apiError?.let {
        // 根据error_code做针对性处理
        when(it.error_code) {
            "BAD_CREDENTIALS" -> {
                // 比如提示用户账号密码错误
            }
            else -> {
                // 处理其他类型的API错误
            }
        }
    } ?: run {
        // 解析错误响应失败,处理通用错误
    }
} catch (e: IOException) {
    // 处理网络异常,比如无网络连接
}

关于Converters、TypeAdapters还是Deserializers?

这里给你理清楚三者的适用场景,帮你做选择:

  • Deserializers(Gson JsonDeserializer):主要用于自定义单个模型或字段的反序列化逻辑,比如某个字段需要特殊格式转换。对全局错误处理来说不是最优选择。
  • TypeAdapters:和Deserializers类似,是Gson的序列化/反序列化工具,适合复杂类型的转换,但同样不是处理API错误响应的首选。
  • Converters(Retrofit Converter):可以自定义Converter.Factory统一处理所有请求的响应,包括成功和失败。但对于suspend函数+HttpException的场景,直接捕获异常并解析是更轻量、更贴合协程风格的方式。

如果你的项目有大量接口需要统一错误处理,还可以封装一个通用的网络请求工具类:

suspend fun <T> safeApiCall(call: suspend () -> T): Result<T> {
    return try {
        Result.success(call())
    } catch (e: HttpException) {
        val apiError = e.parseApiError()
        Result.failure(apiError?.let { CustomApiException(it) } ?: e)
    } catch (e: IOException) {
        Result.failure(NetworkException())
    }
}

// 自定义异常类,方便上层识别错误类型
class CustomApiException(val apiError: ApiError) : Exception(apiError.message)
class NetworkException : Exception("网络连接失败,请检查网络设置")

调用时就会更简洁:

val loginResult = safeApiCall { service.login() }
when(loginResult) {
    is Result.Success -> {
        // 处理登录成功逻辑
    }
    is Result.Failure -> {
        when(loginResult.exception) {
            is CustomApiException -> {
                // 处理自定义API错误
            }
            is NetworkException -> {
                // 处理网络错误
            }
            else -> {
                // 处理其他未知异常
            }
        }
    }
}

这样整个错误处理逻辑就统一且清晰了~

内容的提问来源于stack exchange,提问作者Leonardo Deleon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:33:47