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] }
原因分析
- HTTP规范与服务器实现差异:根据HTTP标准,HEAD请求的响应不应包含请求体,但部分服务器未严格遵循规范,返回了非空的响应体内容。
- Ktor OkHttp引擎校验逻辑:Ktor的OkHttp引擎在处理HEAD请求时,默认会校验响应体长度是否为0,当服务器返回非空响应体时触发该异常。而直接使用OkHttp时,OkHttp会自动忽略HEAD请求的响应体,不会执行严格校验。
- 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
相关产品推荐
相关产品推荐

