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
相关产品推荐
相关产品推荐

