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

Ktor反序列化失败:NoTransformationFoundException问题求助

解决Ktor JSON反序列化NoTransformationFoundException问题

问题本质

io.ktor.client.call.NoTransformationFoundException异常表示Ktor的ContentNegotiation插件无法将响应字节流转换为目标数据类,核心原因通常是依赖缺失、插件配置不全或泛型解析时的类型匹配问题。

解决方案

1. 补全必要依赖

确保Module级别的build.gradle中添加了完整的Ktor序列化相关依赖(以Ktor 2.x版本为例):

dependencies {
    // Ktor核心客户端
    implementation "io.ktor:ktor-client-core-jvm:$ktor_version"
    // Android适配的客户端引擎(推荐OkHttp)
    implementation "io.ktor:ktor-client-okhttp:$ktor_version"
    // ContentNegotiation插件
    implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
    // Kotlinx JSON序列化支持
    implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"
    // Kotlinx序列化核心库
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
}

替换$ktor_version和$serialization_version为你使用的实际稳定版本。

2. 优化ContentNegotiation配置

创建HttpClient时,为JSON序列化添加容错策略,避免因后端返回额外字段或格式宽松导致解析失败:

val client = HttpClient(OkHttp) {
    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true // 忽略data class未定义的字段
            isLenient = true // 兼容非严格的JSON格式
        })
    }
}

3. 修正List类型解析方式

针对列表类型的反序列化,明确指定泛型类型(规避类型擦除带来的匹配问题):

// 替换原写法:val sites: List<SiteResponse> = response.body()
val sites = response.body<List<SiteResponse>>()

4. 单个对象解析的注意事项

LoginResponse的解析逻辑可保持现有写法,但需确保data class字段与JSON响应完全匹配(你的代码中isAdmin等字段大小写已对齐,无问题)。

完整修改示例(loadSites函数)

private suspend fun loadSites() {
    val text = "Loading Sites..."
    val duration = Toast.LENGTH_SHORT
    val toast = Toast.makeText(this, text, duration)
    toast.show()

    val getsitesforcustomerurl = "https://*****************/GetSitesForCustomer/cmd"

    val client = HttpClient(OkHttp) {
        install(ContentNegotiation) {
            json(Json {
                ignoreUnknownKeys = true
                isLenient = true
            })
        }
    }

    val response: HttpResponse = client.post(getsitesforcustomerurl) {
        contentType(ContentType.Application.Json)
        setBody(Customer(58))
    }

    if (response.status.value in 200..299) {
        Log.d(TAG, "Successful Response")
        Log.d(TAG, response.bodyAsText())
        try {
            val sites = response.body<List<SiteResponse>>()
            Log.d(TAG, "Number of sites: ${sites.size}")
        } catch (e: Exception) {
            Log.d(TAG, "Exception: $e")
        }
    }
}

额外提示

  • 确保所有数据类的@Serializable注解来自kotlinx.serialization.Serializable
  • 不要在调用bodyAsText()后再调用body(),前者会消耗响应流导致后续解析失败
  • 尽量全局复用HttpClient实例,避免每次请求创建新客户端

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 04:15:31