Kotlin中如何处理Retrofit成功与错误两种不同响应结构?
结论
强烈建议使用sealed class(密封类)实现对应逻辑,不要合并为单个data class
合并为单个data class的弊端
你示例的合并写法存在严重的设计缺陷:
- 成功响应不含
detail字段、错误响应不含access_token和token_type字段,你写的Auth类所有字段均为非空类型,任何一种响应返回时都会因为缺失字段触发序列化失败,直接导致App崩溃 - 即使将所有字段改为可空类型,后续业务逻辑处理时需要反复做非空校验,既冗余也容易因误判产生空指针异常,无法利用Kotlin的空安全特性
- 两种完全独立的业务场景(登录成功/登录失败)耦合在同一个类中,代码可读性差,后续维护成本极高
密封类实现方案
密封类可以限定响应只有成功、错误两种类型,每个类型持有自己独有的字段,天然适配异构响应的场景,示例代码如下:
// 密封类根类,限定认证响应只有两种类型 sealed class AuthResponse // 登录成功响应实体 data class AuthSuccess( val access_token: String, val token_type: String ) : AuthResponse() // 错误详情条目实体 data class ErrorDetail( val loc: List<String>, val msg: String, val type: String ) // 登录失败响应实体 data class AuthError( val detail: List<ErrorDetail> ) : AuthResponse()
后续处理响应时直接通过when表达式分支处理即可,编译器会自动校验是否覆盖所有分支,无需额外判空,逻辑清晰安全:
fun handleAuthResult(response: AuthResponse) { when(response) { is AuthSuccess -> { // 直接使用token走登录成功逻辑 saveAccessToken(response.access_token) navigateToHome() } is AuthError -> { // 直接取错误信息提示用户 val errorMsg = response.detail.firstOrNull()?.msg ?: "登录失败,请稍后重试" showToast(errorMsg) } } }
如果使用Retrofit做网络请求,只需要自定义一个Converter适配器,根据HTTP状态码(比如200走成功解析逻辑、4xx走错误解析逻辑)将返回值解析为对应子类实例即可,无需手动处理字段兼容问题。
内容的提问来源于stack exchange,提问作者FrensisXh
相关产品推荐
相关产品推荐

