Flask中正确设置SSE需用Response构造流式响应,显式指定content_type="text/event-stream"、Cache-Control: no-cache,并在生成器中按SSE协议yield"data: ...\n\n"格式消息。

Flask 中如何正确设置 SSE 响应头和流式响应
SSE 要求服务端返回 text/event-stream MIME 类型、禁用缓存、保持连接长开,而 Flask 默认响应会缓冲并关闭连接。直接用 return 返回字符串或 JSON 不起作用——必须用 Response 构造流式响应,并手动控制 headers。
关键点:
-
content_type="text/event-stream"必须显式指定,不能依赖jsonify或默认推断 - 必须设置
Cache-Control: no-cache,否则浏览器可能缓存旧事件 - 需禁用 Flask 的自动响应包装(如
make_response会加额外 header),推荐用Response构造器直写 - 流式生成器函数里每条消息末尾必须有双换行
\n\n,这是 SSE 协议硬性要求
用生成器函数实现事件推送逻辑
SSE 的核心是服务端持续 yield 格式化消息,Flask 通过生成器函数配合 Response 实现流式传输。不要试图在普通视图里循环 sleep + return —— 那只会返回单次响应。
示例结构:
立即学习“Python免费学习笔记(深入)”;
from flask import Response, Flask
import time
app = Flask(__name__)
def event_stream():
for i in range(5):
yield f"data: {{\"count\": {i}}}\n\n"
time.sleep(1)
@app.route('/events')
def sse():
return Response(event_stream(), content_type="text/event-stream")
注意:data: 前缀不可省略,id: 和 event: 字段按需添加;每次 yield 后必须有两个换行,否则浏览器无法解析为独立事件。
处理客户端断连与连接保活
浏览器标签页切换、网络抖动、Nginx 等反向代理超时都会导致连接中断。Flask 本身不感知断连,生成器继续运行会造成资源泄漏或重复推送。
应对方式:
- 在生成器中定期检查
request.environ.get("wsgi.errors")是否仍可写(不通用);更可靠的是捕获GeneratorExit或BrokenPipeError - 添加心跳事件:每 15–30 秒
yield ":keep-alive\n\n"(冒号开头为注释,不触发 JSonmessage) - 若使用 Nginx,务必配置
proxy_buffering off;、proxy_cache off;、proxy_read_timeout 300; - 避免在生成器中做阻塞 I/O(如数据库查询),否则整个流卡住;改用异步任务+队列+轮询检查
前端 JavaScript 如何稳定接收并重连
原生 EventSource 对错误恢复能力有限,onerror 触发后不会自动重试,且不支持自定义请求头或凭据携带(除非显式设 withCredentials: true)。
实操建议:
- 始终监听
onerror并手动重建实例,例如setTimeout(() => new EventSource(...), 3000) - 服务端发送
retry: 5000\n\n可影响浏览器默认重连间隔(但部分浏览器忽略) - 若需带 Cookie 或认证头,必须后端允许 CORS(
Access-Control-Allow-Credentials: true)且前端设withCredentials: true - 调试时用
curl -N http://localhost:5000/events直接看原始流输出,比浏览器 DevTools 更直观
真正麻烦的从来不是第一次连上,而是连接维持期间的异常检测粒度、服务端状态同步、以及代理层对 chunked transfer 的截断行为——这些地方出问题,现象都是“突然不收消息了”,但原因各不相同。


















