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

如何处理Ktor ContentNegotiation遇到意外响应时的序列化错误?

处理Ktor ContentNegotiation中的意外错误响应

在使用Ktor的ContentNegotiation做JSON序列化时,遇到服务端返回非预期的错误负载(比如含error字段的结构)导致JsonConvertException,可以通过以下几种方式解决:

方法一:根据HTTP状态码条件解析响应

服务端返回错误时通常会伴随非2xx的状态码,先获取完整响应对象,根据状态码选择对应的序列化类型,从根源避免触发序列化异常:

  1. 定义正常响应和错误响应的数据类:
@Serializable
data class NormalResponse(val data: YourDataModel)

@Serializable
data class ErrorResponse(val error: ErrorInfo)

@Serializable
data class ErrorInfo(val code: Int, val message: String)
  1. 发起请求时先获取HttpResponse对象,再根据状态码分支解析:
val client = HttpClient(OkHttp) {
    install(ContentNegotiation) {
        Json {
            ignoreUnknownKeys = true // 忽略响应中的未知字段,提升兼容性
            isLenient = true
        }
    }
}

val response = client.post("https://apis.google.com/some-service") {
    // 配置请求体、Headers等参数
}

when {
    response.status.isSuccess() -> {
        val normalData = response.body<NormalResponse>()
        // 处理正常业务逻辑
    }
    else -> {
        val errorData = response.body<ErrorResponse>()
        // 处理错误逻辑,比如展示error.message
    }
}

方法二:捕获序列化异常后手动解析错误

如果服务端错误响应仍返回2xx状态码(这种场景较少见),可以捕获JsonConvertException,读取原始响应内容后手动解析为错误结构:

try {
    val normalData = client.post("https://apis.google.com/some-service") {
        // 请求配置
    }.body<NormalResponse>()
    // 处理正常响应
} catch (e: JsonConvertException) {
    // 读取原始响应文本
    val rawResponse = client.post("https://apis.google.com/some-service") {
        // 复用之前的请求配置
    }.body<String>()
    
    // 手动解析为错误响应
    val errorData = Json.decodeFromString<ErrorResponse>(rawResponse)
    // 处理错误逻辑
}

提示:如果不想重复发起请求,可以改用client.execute获取HttpCall对象,先尝试解析正常响应,失败后直接读取call.response.content()的内容,避免二次请求。

额外优化:用密封类统一响应类型

可以定义密封类封装正常和错误响应,让代码更简洁易维护:

sealed class ApiResponse<out T> {
    data class Success<out T>(val data: T) : ApiResponse<T>()
    data class Error(val errorInfo: ErrorInfo) : ApiResponse<Nothing>()
}

// 扩展函数简化解析流程
suspend fun <T> HttpResponse.parseResponse(): ApiResponse<T> where T : @Serializable {
    return try {
        if (status.isSuccess()) {
            ApiResponse.Success(body<T>())
        } else {
            ApiResponse.Error(body<ErrorResponse>().error)
        }
    } catch (e: JsonConvertException) {
        val errorRaw = body<String>()
        val errorResp = Json.decodeFromString<ErrorResponse>(errorRaw)
        ApiResponse.Error(errorResp.error)
    }
}

使用时只需:

val response = client.post("https://apis.google.com/some-service") {
    // 请求配置
}.parseResponse<NormalResponse>()

when (response) {
    is ApiResponse.Success -> {
        // 处理response.data
    }
    is ApiResponse.Error -> {
        // 处理response.errorInfo
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:36:26