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

Ktor HEAD请求抛出"expected 0 bytes but received 20"异常求助

Ktor 3.0.0-rc-1 + OkHttp引擎HEAD请求抛出IOException的问题解决

问题场景

在Android端使用Ktor 3.0.0-rc-1搭配OkHttp引擎发起HEAD请求获取指定Header时,持续抛出异常:

java.io.IOException: expected 0 bytes but received 20
  • Retrofit实现及直接使用OkHttp(代码如下)均能正常运行:
    val client = OkHttpClient.Builder().followRedirects(true).build()
    
  • 项目为跨平台架构,无法替换为Retrofit或直接OkHttp实现
  • 已尝试禁用插件、创建全新HttpClient、调整引擎配置等方案,均未解决问题
  • 复现代码:
    suspend fun getHeaderValue(header: String): String? {
        return client.head(url) {
            // 添加自定义Header
        }.headers[header]
    }
    

原因分析

  1. HTTP规范与服务器实现差异:根据HTTP标准,HEAD请求的响应不应包含请求体,但部分服务器未严格遵循规范,返回了非空的响应体内容。
  2. Ktor OkHttp引擎校验逻辑:Ktor的OkHttp引擎在处理HEAD请求时,默认会校验响应体长度是否为0,当服务器返回非空响应体时触发该异常。而直接使用OkHttp时,OkHttp会自动忽略HEAD请求的响应体,不会执行严格校验。
  3. RC版本潜在bug:Ktor 3.0.0-rc-1为候选发布版本,可能存在OkHttp引擎与HEAD请求适配的未修复bug。

解决思路

1. 自定义OkHttp客户端拦截器,修正HEAD响应

通过添加拦截器,强制将HEAD请求的响应体置为空,同时修改Content-Length为0,适配Ktor的校验逻辑:

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val originalResponse = chain.proceed(chain.request())
        val request = chain.request()
        if (request.method.equals("HEAD", ignoreCase = true)) {
            // 清空响应体并设置Content-Length为0
            originalResponse.newBuilder()
                .body(ResponseBody.create(null, ByteArray(0)))
                .header("Content-Length", "0")
                .build()
        } else {
            originalResponse
        }
    }
    .followRedirects(true)
    .build()

// 配置Ktor使用自定义OkHttp客户端
val client = HttpClient(OkHttp) {
    engine {
        preconfigured = okHttpClient
    }
}

2. 降级至Ktor稳定版

暂时切换到Ktor 2.x系列稳定版本,RC版本的HEAD请求适配问题可能已在稳定分支中修复。

3. 提交官方Issue反馈

向Ktor官方仓库提交问题,提供复现步骤、服务器响应信息及异常栈,推动官方修复该引擎的校验逻辑问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:38:19