SSE(Server-Sent Events,服务器发送事件)让服务端通过一条保持打开的 HTTP 连接,连续向客户端发送事件。它适合任务进度、日志和通知等服务器单向推送场景。
为什么普通响应不够用
普通 HTTP 请求通常只返回一次结果:
请求 --------> 处理 --------> 一次性响应
文章解析可能持续几十秒。若等待最终响应,客户端不知道任务是否仍在运行。SSE 可以在处理期间不断发送状态:
请求 --------> progress: 10% --> progress: 40% --> completed
SSE 如何工作
服务端返回 Content-Type: text/event-stream,并保持连接。事件由文本行组成,事件之间以空行分隔:
event: progress
data: {"progress":40,"message":"Generating explanations"}
event: completed
data: {"article_id":42}
客户端逐个读取事件并更新界面,直到任务完成、失败或连接关闭。
与其他方式的区别
| 方式 | 通信方向 | 适合场景 | 代价 |
|---|
| 轮询 | 客户端反复请求 | 简单、低频状态检查 | 有延迟且产生重复请求 |
| SSE | 服务端持续推送给客户端 | 进度、通知、日志 | 主要是单向通信 |
| WebSocket | 双向持续通信 | 聊天、协作编辑、实时控制 | 协议与连接管理更复杂 |
RakuLLApp 只需要服务端推送处理进度,因此 SSE 比 WebSocket 更直接。
RakuLLApp 的任务流程
- 客户端提交上传或重新生成请求。
- Controller 创建内存任务并立即返回
task_id。
- 客户端订阅
GET /api/tasks/{id}/progress。
- Controller 编排 Agent 和 Model,并通过 SSE 推送进度。
- 客户端收到
completed 或 failed 后结束监听。
反向代理若缓冲响应,客户端会在最后一次性收到所有事件,看起来就像 SSE 没有工作。进度端点必须关闭代理缓冲和缓存。
SSE 连接也可能因网络中断而关闭,所以客户端仍需处理超时、失败和重试。当前项目的完整调用顺序见 数据流。