基于KTOR实现文件流式中转:从外部API取流实时响应客户端
KTOR流式代理转发大文件解决方案
我有一个作为前端客户端与外部REST API之间代理的KTOR后端,需要实现KTOR从外部REST API分块获取文件,收到文件块后立即转发给客户端,不需要临时存储整个文件(因为文件可能极大,只能用流式处理)。
当前编写的代码无法正常工作:
get("/file") { val uri = "/rest-api" downloadFileClient.prepareGet(uri).execute {response -> call.respondOutputStream(ContentType.Application.Pdf, HttpStatusCode.OK, producer = {response.bodyAsChannel()}) } }
问题原因
respondOutputStream的producer参数需要的是向OutputStream写入数据的逻辑,但直接传入response.bodyAsChannel()无法完成通道到输出流的正确转换,导致数据无法正常转发。
修复后的代码
get("/file") { val uri = "/rest-api" downloadFileClient.prepareGet(uri).execute { externalResponse -> // 透传外部API的响应头部与状态码 call.response.status(externalResponse.status) externalResponse.headers.forEach { key, values -> values.forEach { value -> call.response.header(key, value) } } // 流式转发:将外部API的响应通道数据直接复制到客户端输出通道 val clientOutputChannel = call.response.outputChannel() externalResponse.bodyAsChannel().copyTo(clientOutputChannel) clientOutputChannel.close() } }
关键说明
- 通道桥接:使用
call.response.outputChannel()获取客户端响应的输出通道,通过copyTo方法直接将外部API返回的响应通道数据复制过去,实现分块流式传输,全程无中间文件存储。 - 头部透传:完整复制外部API的响应头部,包括Content-Type、ContentLength、Transfer-Encoding等,确保客户端能正确解析和处理大文件。
- 资源释放:完成数据复制后关闭输出通道,保证HTTP响应正常结束,避免连接泄漏。
额外注意事项
- 确保
downloadFileClient的配置支持流式响应,不要启用会缓存整个响应的设置(比如某些默认的拦截器)。 - 如果外部API采用分块编码(Transfer-Encoding: chunked),KTOR会自动处理分块逻辑,无需额外代码。
内容的提问来源于stack exchange,提问作者Tmfwang
相关产品推荐
相关产品推荐

