KMM中使用Ktor全局处理HTTP响应码及异常问题咨询
全局搞定KMM中Ktor的HTTP错误码处理
嘿,刚探索KMM就遇到这种全局统一处理HTTP错误的需求,太正常了!我来帮你拆解下问题,再给你靠谱的解决方案:
首先说下你代码里的两个小问题:
ResponseObserver本来就是只在**响应成功(2xx状态码)**的时候才会触发回调,错误状态码走的是异常分支,所以它确实不会捕获到401、404这些情况- 你写的
HttpResponseValidator看起来没生效,但其实Ktor自带的默认验证器已经在干活了——不然你在getUsers的catch里也抓不到404异常对吧?只是你的自定义验证逻辑可能没被正确执行而已
下面给你两种实用的全局处理方案,任选其一都能解决“不想每个请求写重复try-catch”的问题:
方案一:自定义HttpResponseValidator + 全局异常处理
这个方案是利用Ktor自带的验证机制,把所有错误码的处理逻辑集中在一处,非常规整:
修改你的HttpClient配置:
private val httpClient = HttpClient { install(JsonFeature) { val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true } serializer = KotlinxSerializer(json) } // 重写HttpResponseValidator,接管所有响应的验证 HttpResponseValidator { validateResponse { response -> val statusCode = response.status.value println("HTTP status: $statusCode") // 按状态码分类抛出异常 when (statusCode) { in 300..399 -> throw RedirectResponseException(response) in 400..499 -> throw ClientRequestException(response) in 500..599 -> throw ServerResponseException(response) } if (statusCode >= 600) { throw ResponseException(response) } } // 在这里统一处理所有HTTP异常,这就是你要的全局处理入口! handleResponseException { cause -> when (cause) { is ClientRequestException -> { val code = cause.response.status.value when (code) { 401 -> { // 比如跳转到登录页、自动刷新token,这里写你的业务逻辑 println("全局处理:401未授权") } 404 -> { println("全局处理:404资源不存在") } else -> { println("全局处理:客户端错误 $code") } } } is ServerResponseException -> { println("全局处理:服务器错误 ${cause.response.status.value}") } is RedirectResponseException -> { println("全局处理:重定向 ${cause.response.status.value}") } else -> { println("全局处理:其他HTTP异常 ${cause.message}") } } // 如果需要让上层请求感知到异常,就重新抛出;不想让上层处理就注释掉这行 throw cause } } }
然后再封装一个通用的请求工具函数,彻底告别每个接口写try-catch:
// 通用请求包装,处理非HTTP的通用异常 private suspend inline fun <reified T> safeRequest(crossinline request: suspend () -> T): T? { return try { request() } catch (e: Exception) { // 这里可以加一些跨平台的错误提示,比如Android弹Toast、iOS弹Alert println("请求出错:${e.message}") null } }
之后调用接口就变得很简洁:
override suspend fun getUsers(): List<User> { return safeRequest { httpClient.get("some url....") } ?: emptyList() }
方案二:用拦截器提前拦截所有响应
如果你想更灵活地在响应到达业务代码前就处理状态码,可以用Ktor的拦截器机制:
private val httpClient = HttpClient { install(JsonFeature) { val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true } serializer = KotlinxSerializer(json) } // 添加响应拦截器,所有响应都会经过这里 sendPipeline.intercept(HttpSendPipeline.After) { response -> val statusCode = response.status.value println("HTTP status: $statusCode") // 直接在这里处理各种状态码 when (statusCode) { 401 -> println("全局拦截到401,处理授权逻辑") 404 -> println("全局拦截到404,处理资源不存在") 500 -> println("全局拦截到500,处理服务器错误") } // 如果是错误状态码,手动抛出异常让上层捕获(可选) if (statusCode >= 400) { when (statusCode) { in 400..499 -> throw ClientRequestException(response) in 500..599 -> throw ServerResponseException(response) } } // 继续传递响应 proceed(response) } }
这种方式能更早介入响应处理,适合需要在验证前做一些操作的场景。
为啥你原来的HttpResponseValidator没生效?
其实Ktor自带的默认HttpResponseValidator已经包含了4xx、5xx的验证逻辑,当你自己定义validateResponse时,默认逻辑会被覆盖,但你能抓到404异常,说明默认验证器还在工作——可能是Ktor版本差异,或者配置写法的小问题。用上面的方案一明确重写验证逻辑,就能确保你的代码被执行啦。
内容的提问来源于stack exchange,提问作者dor506
相关产品推荐
相关产品推荐

