Django+Daphne下StreamingHttpResponse无法逐块输出的配置问询
我用Django的StreamingHttpResponse开发API,按设计它应该按yield的单元输出结果,但实际是攒够约4000字符的缓冲块才返回。
示例生成器代码
def iterator(): for i in range(100000): yield {"iteration ":str(i)}
预期输出
{"iteration" : "1"} {"iteration" : "2"} ...
实际输出
{"iteration" : "1"} {"iteration" : "2"} ~~ {"iteration" : "100"}
配置调整方案
1. 强制StreamingHttpResponse逐块输出
初始化StreamingHttpResponse时设置chunk_size=1,禁用内部缓冲;同时要把生成器里的字典转成字符串并换行,确保每个yield是独立可识别的单元:
import json from django.http import StreamingHttpResponse def stream_view(request): def iterator(): for i in range(100000): # 转成字符串+换行,避免Django自动序列化合并 yield f"{json.dumps({'iteration': str(i)})}\n" response = StreamingHttpResponse(iterator(), content_type='application/jsonl') response.chunk_size = 1 # 关键设置,强制每次输出最小单元 return response
2. 关闭Daphne的响应缓冲
Daphne作为ASGI服务器默认会做缓冲优化,需要调整配置:
- 启动时添加参数:
daphne --http-buffer-size=1 your_project.asgi:application
- 或在
daphne.yml配置文件中设置:
http_buffer_size: 1
3. 排除流式响应的中间件缓冲
部分中间件(如GZipMiddleware)会压缩缓冲响应,需要跳过流式请求:
- 在视图上添加装饰器,仅对非流式响应启用压缩:
from django.views.decorators.gzip import gzip_page @gzip_page(condition=lambda request, response: not isinstance(response, StreamingHttpResponse)) def stream_view(request): # 视图逻辑 pass
- 若不需要全局压缩,直接在
settings.py中移除GZipMiddleware。
4. 验证客户端接收
部分客户端(如浏览器)自身有缓冲,测试建议用curl命令:
curl -N http://your-api-url/stream-endpoint
-N参数会禁用curl内部缓冲,确保实时接收每个chunk。
实际日志(翻译后)
2023-11-10 05:29:58,361 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,376 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,398 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,412 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,432 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,461 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,475 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,491 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,515 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,533 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
2023-11-10 05:29:58,572 DEBUG 8 --- [主线程] daphne.http_protocol:283 针对['192.168.192.1', 0]的HTTP响应块 --- [7f6f53f9c0a393a547dccbdde2c59065] [24a60a12badf08b6] [用户:6549c3c2c8fd4d4d6099d6d1]
此时我能看到API的响应。2023-11-10 05:29:58,603 DEBUG 8 --- [主线程] daphne.http_protocol:160 针对['127.0.0.1', 32880]的HTTP b'GET'请求 --- [-] [-] [-]
内容的提问来源于stack exchange,提问作者JuYeong Park

