如何在Ktor HTTP Client中监控请求进度?
在Kotlin多平台项目中用Ktor HTTP Client监控下载进度
嗨,我来帮你搞定这个问题!针对你使用的Ktor 1.2.5版本(CIO引擎),要给HTTP请求加上下载进度监控,有两种实用的实现方式,具体如下:
方式一:针对单个请求手动监控进度
这种方式适合只需要给特定请求添加进度监控的场景,不需要修改全局客户端配置:
// 初始化CIO客户端 val client = HttpClient(CIO) // 发起请求并获取原始HttpResponse val response = client.get<HttpResponse>("https://stackoverflow.com/") // 获取响应内容总长度(可能为null,默认设为0) val contentLength = response.contentLength() ?: 0L var downloadedBytes = 0L val buffer = ByteBuffer.allocate(8192) // 8KB缓冲区,可根据需求调整 val responseBodyBuilder = StringBuilder() // 循环读取响应体字节流,同时更新进度 while (!response.content.isClosedForRead) { val bytesRead = response.content.readAvailable(buffer) if (bytesRead <= 0) break downloadedBytes += bytesRead // 调用你的进度更新函数 progress(downloadedBytes, contentLength) // 将读取的字节转为字符串,拼接成最终响应体 buffer.flip() responseBodyBuilder.append(Charsets.UTF_8.decode(buffer)) buffer.clear() } // 最终的响应体文本 val responseBody = responseBodyBuilder.toString()
方式二:全局拦截器实现所有请求自动监控
如果你的项目中有多个请求都需要进度监控,推荐用这种全局拦截器的方式,一次配置所有请求生效:
// 初始化带有进度监控拦截器的CIO客户端 val client = HttpClient(CIO) { install(HttpSend) { intercept { request -> // 执行原始请求获取响应 val originalResponse = execute(request) val contentLength = originalResponse.contentLength() ?: 0L var downloadedBytes = 0L // 包装原始响应的字节流,添加进度监控逻辑 val monitoredContent = object : ByteReadChannel by originalResponse.content { override suspend fun readAvailable(dst: ByteBuffer): Int { val bytesRead = originalResponse.content.readAvailable(dst) if (bytesRead > 0) { downloadedBytes += bytesRead // 调用你的进度更新函数 progress(downloadedBytes, contentLength) } return bytesRead } } // 返回包装后的响应,后续读取响应体时会自动触发进度更新 originalResponse.copy(content = monitoredContent) } } } // 正常发起请求即可,进度会自动触发 val responseBody = client.get<String>("https://stackoverflow.com/")
注意事项
- 响应的
contentLength()可能返回null(比如服务器没返回Content-Length头),这种情况下contentLength会被设为0,进度函数里只能获取已下载字节数,总长度未知。 - 以上代码完全适配你使用的Ktor 1.2.5版本,不同版本的API可能有差异,不要随意升级版本后直接复用。
- 如果需要监控上传进度,逻辑会有所不同,但你的问题只涉及下载进度,所以这里就不展开啦。
内容的提问来源于stack exchange,提问作者Mirt
相关产品推荐
相关产品推荐

