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

Ktor调用API时出现-1未知状态码及ContentType:null的运行时修复求助

运行时修复Ktor客户端NoTransformationFoundException(状态码-1)问题

问题背景

调用API时偶尔出现以下响应日志:

13:12:23.142 System.out               I  HttpClient: RESPONSE: -1 Unknown Status Code
13:12:23.142 System.out               I  METHOD: HttpMethod(value=POST)
13:12:23.142 System.out               I  FROM: https://webservice.azurewebsites.net/en/Dispatch/getTickets
13:12:23.142 System.out               I  COMMON HEADERS
13:12:23.142 System.out               I  -> content-length: 0
13:12:23.142 System.out               I  -> date: Wed, 25 Sep 2024 07:42:23 GMT
13:12:23.142 System.out               I  -> server: Microsoft-IIS/10.0
13:12:23.142 System.out               I  -> set-cookie: ARRAffinity=6dec0997e21dec30ce7ef102ebaec80934d28e2723296e23b047a25a64c195a9;Path=/;HttpOnly;Secure;Domain=webservice.azurewebsites.net; ARRAffinitySameSite=6dec0997e21dec30ce7ef102ebaec80934d28e2723296e23b047a25a64c195a9;Path=/;HttpOnly;SameSite=None;Secure;Domain=webservice.azurewebsites.net
13:12:23.142 System.out               I  -> www-authenticate: Bearer error="invalid_token", error_description="The token expired at '09/25/2024 07:22:35'"
13:12:23.142 System.out               I  -> x-android-received-millis: 1727250143135
13:12:23.142 System.out               I  -> x-android-response-source: NETWORK 401
13:12:23.142 System.out               I  -> x-android-selected-protocol: http/1.1
13:12:23.142 System.out               I  -> x-android-sent-millis: 1727250142738
13:12:23.142 System.out               I  -> x-powered-by: ASP.NET
13:12:23.142 System.out               I  BODY Content-Type: null
13:12:23.142 System.out               I  BODY START
13:12:23.142 System.out               I  
13:12:23.142 System.out               I  BODY END

随后触发崩溃,日志如下:

Expected response body of the type 'class app.models.Response' but was 'class io.ktor.utils.io.ByteBufferChannel'
In response from `https://webservice.azurewebsites.net/en/Dispatch/getTickets`
Response status `-1 Unknown Status Code`
Response header `ContentType: null` 
Request header `Accept: application/json`
                                         
io.ktor.client.call.NoTransformationFoundException: Expected response body of the type 'class app.models.Response' but was 'class io.ktor.utils.io.ByteBufferChannel'

In response from `https://webservice.azurewebsites.net/en/Dispatch/getTickets`
Response status `-1 Unknown Status Code`
Response header `ContentType: null` 
Request header `Accept: application/json`
                                         
at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:94)
at app.service.WebService$DispatchService.getTickets(WebService.kt:1088)
at app.service.WebService$DispatchService$getTickets$1.invokeSuspend(Unknown Source:15)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

已尝试通过以下代码处理-1状态码并重置令牌,但未解决问题:

ResponseObserver { response ->
                if (response.status.value == -1 && response.contentType() == null ) {
                    resetToken()
                }
            }

仅重启Android应用可临时解决,需实现运行时修复方案。


解决方案

1. 全局拦截异常,避免崩溃并触发重试

在Ktor客户端配置中添加响应异常处理器,捕获NoTransformationFoundException,针对状态码-1+ContentType=null的场景,触发重试逻辑:

// 自定义重试标记异常
class RetryRequestException : Exception()

val httpClient = HttpClient(Android) {
    // 配置内容协商(确保已添加JSON转换器)
    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true
        })
    }
    // 配置重试插件
    install(Retry) {
        retryOnExceptionIf(3) { _, exception ->
            exception is RetryRequestException
        }
    }
    // 响应验证器,拦截异常
    HttpResponseValidator {
        handleResponseException { exception ->
            if (exception is NoTransformationFoundException) {
                val call = exception.call
                if (call.response.status.value == -1 && call.response.contentType() == null) {
                    throw RetryRequestException()
                }
            }
        }
    }
    // 其他配置:超时、日志等
}

2. 重置HttpClient实例(核心修复)

状态码-1通常意味着客户端网络实例处于异常状态(如连接池损坏、SSL会话异常),此时复用原有实例会持续触发问题,需重建实例:

// 单例管理HttpClient实例
object HttpClientManager {
    private var client: HttpClient? = null

    fun getClient(): HttpClient {
        return client ?: createNewClient().also { client = it }
    }

    fun resetClient() {
        // 关闭旧实例释放资源
        client?.close()
        // 创建新实例
        client = createNewClient()
    }

    private fun createNewClient(): HttpClient {
        return HttpClient(Android) {
            install(ContentNegotiation) {
                json(Json { ignoreUnknownKeys = true })
            }
            // 复制原有客户端的所有配置
        }
    }
}

在异常拦截中调用重置方法:

HttpResponseValidator {
    handleResponseException { exception ->
        if (exception is NoTransformationFoundException) {
            val call = exception.call
            if (call.response.status.value == -1 && call.response.contentType() == null) {
                HttpClientManager.resetClient()
                throw RetryRequestException()
            }
        }
    }
}

3. 强制指定响应类型转换

在请求时手动指定转换类型,避免Ktor因ContentType=null找不到转换器:

suspend fun getTickets(): Response? {
    return runCatching {
        HttpClientManager.getClient().post("https://webservice.azurewebsites.net/en/Dispatch/getTickets") {
            // 请求参数、header配置
            headers {
                append("Accept", "application/json")
            }
        }.body<Response>()
    }.getOrElse { exception ->
        if (exception is NoTransformationFoundException) {
            HttpClientManager.resetClient()
            // 返回默认值或null,避免崩溃
            null
        } else {
            throw exception
        }
    }
}

总结

问题根源是Ktor客户端实例因底层网络异常进入无效状态,导致无法处理无ContentType的响应。通过异常拦截+重置客户端+重试的组合方案,可在运行时修复该问题,无需重启应用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 01:05:58