aiohttp 3.0+中不调用drain如何发送多部分请求
核心问题澄清与正确实现方式
首先纠正两个最容易踩的认知误区:
- 被标记废弃的
StreamResponse.drain()绝对不能替换为write_eof()write_eof()的作用是标记当前HTTP响应的内容传输全部完成,触发连接关闭流程,和逐帧推送的长连接场景完全不匹配。如果在每帧发送后调用这个方法,第一帧传输完成后连接就会直接断开,根本无法实现持续的MJPEG流推送效果。 drain()对应的背压控制能力 并没有被移除
aiohttp 3.0版本的API架构调整,只是把原来绑定在StreamResponse上的数据写入、缓冲区等待类逻辑,拆分到了独立的PayloadWriter组件上。原来的drain()方法只是做了带废弃标记的兼容封装,核心的“等待发送缓冲区排空”的能力一直保留,只是调用路径发生了变化。
具体代码替换方案
原代码中await response.drain()的核心作用是实现传输背压控制:当应用层的待发送数据堆积超过缓冲区阈值时,挂起当前协程,等底层TCP把缓冲区的数据全部发送完成后再继续执行,避免因为生产速度远快于网络传输速度,导致服务器内存被快速堆积的待发送数据占满。
当前版本下,这个逻辑的等价替换写法为:
# 替换原代码中废弃的 await response.drain() await response._writer.drain()
实际实现时需要注意几个细节:
- 初始化
StreamResponse实例后,必须先执行await response.prepare(request)完成响应头的发送,否则后续的逐帧写入操作会触发运行时异常,原示例代码遗漏了这步必要逻辑。 MultipartWriter.write()方法内部本身就会在完成单段内容写入后触发一次缓冲区状态检查,手动调用writer的drain()可以实现和原废弃方法完全一致的背压控制效果。- 官方示例中沿用的drain调用逻辑没有触发废弃警告,是因为示例里的drain是
MultipartWriter内部调用的底层writer方法,不是被标记废弃的StreamResponse兼容封装方法。
内容的提问来源于stack exchange,提问作者Max Voitko
相关产品推荐
相关产品推荐

