假设你是一家高档日料店的常客。以前,你点一份套餐,后厨必须把所有菜品——前菜、刺身、天妇罗、甜品——全部备齐,才由服务员一次性端上桌。你饿着肚子干等十五分钟,而真正好吃的第一贯寿司早就该在五分钟时送到你嘴里了。这就是传统 HTTP 请求的体验:请求发出去,服务器默默憋大招,最后“哗”地一下把完整响应砸回来。 现在,这家店换了经营模式:吧台后面多了一条旋转传送带。后厨每捏好一贯寿司,立刻放在传送带上,你眼前随时出现刚出锅的美食,边吃边等,体验拉满。这就是 SSE(Server-Sent Events)——服务器像传送带一样,把数据“一条一条”推到客户端,让大模型的回答像打字一样逐字呈现。 本文带你彻底搞懂 SSE 的协议原理、与 WebSocket 的区别,以及如何在 Python 中亲手实现一个 SSE 流式接口。读完你不仅能看懂大模型聊天界面的底层机制,还能自己动手写一个。
对 LLM 应用工程师而言,SSE 是撬动“实时交互体验”的杠杆——掌握它,你就能开发出像 ChatGPT 一样逐字输出的对话应用,这是 AI 产品落地的核心技能之一。
目录
可视化演示
展示SSE流式输出中Token逐字推送过程、SSE与WebSocket单向/双向通信对比,以及EventSource事件流格式解析。
本节配有交互动效(进入视口后自动加载,约 3KB)。
流式传输:Token逐字推送 服务器逐Token推送,客户端实时渲染 每个Token间隔~120ms模拟LLM生成 首字延迟低,用户体验显著提升 TTFB \u2248 200ms,逐字呈现无需等待全量
为什么需要流式输出
你有没有注意过,在 ChatGPT 问世之前,几乎所有的“AI 问答”功能都是一个死板的流程:你点击“提交”按钮,页面转圈,三五秒甚至十几秒后,一整段文字“啪”地出现在屏幕上。可 ChatGPT 不一样——它像一位打字飞快的秘书,你在屏幕上看着一个字一个字被打出来。这两种体验的差别,就像“在餐厅里饿着肚子等一桌菜上齐”和“坐在吧台前看着寿司师傅现捏现送”。
这种体验上的革命,背后就是流式输出技术。传统 HTTP 请求是一次性的:客户端发一个请求,服务器把所有数据处理完,再一次性返回完整响应。在这个模型下,大模型生成 500 字回答需要 10 秒,用户就必须对着转圈的空屏等 10 秒。注意,这 10 秒里用户其实完全无事可做——而这 10 秒恰恰是“对话感”消失的元凶。
流式输出彻底改变了这个体验。服务器一旦开始生成内容,就立刻把已经生成的片段发送给客户端,用户看到的不是“一张白纸等 10 秒”,而是“屏幕上第 1 秒就开始蹦字”。心理学上有个概念叫“感知性能”——用户对等待的忍受度,往往取决于有没有进度反馈。流式输出让“等待”变成了“观看过程”,把 10 秒的煎熬变成 10 秒的期待。
所以,流式输出解决的不是“生成速度问题”,而是“等待体验问题”——它把后厨悄悄备菜,变成了开放厨房里的现场料理秀。对你未来的 AI 产品而言,这可能就是用户留存率的分水岭。
- 感知等待时间用户主观感受到的等待时长,由实际等待时间和进度反馈密度共同决定。
- 实际等待时间从发起到得到完整结果的真实耗时,流式输出不能减少它,但能“稀释”它。
- 进度反馈密度单位时间内用户看到的反馈次数,逐字输出让这个值接近无穷大。
SSE 协议核心机制
想象这条传送带本身:它看似一直在动,但物理结构只是一条固定在吧台上的滚轴带,不需要每次传菜都重新架一条。SSE 就是这条固定的传送带——客户端和服务器之间只建立一个 HTTP 连接,然后这个连接一直保持着,服务器源源不断地把数据放在上面推给客户端。
SSE 全称 Server-Sent Events(服务器发送事件),名字直白:就是“服务器发送过来的事件”。它基于普通的 HTTP 协议,但使用了 Content-Type: text/event-stream 这个特殊的 MIME 类型来标记响应。一旦浏览器看到这个类型,就知道“这不是一次性响应,而是会持续推送的流”。连接建立后,服务器可以随时向客户端发送消息——注意,是“随时”,不需要客户端再次请求。
SSE 的消息格式非常有规律,像传送带上的寿司碟子,每碟都有固定的摆盘规则。一条 SSE 消息由若干字段行组成,最常见的是 data: 字段;消息之间用空行分隔。举个最简例子:
这一行 data: 你好 加一个空行,就是一条完整的 SSE 消息。服务器可以持续发送多个这样的块。浏览器端通过 EventSource API 接收,每收到一条 data 消息,就会触发一个 onmessage 回调。一个用起来异常简单的 API——不需要处理复杂的状态码,不需要握手升级协议。
SSE 还内置了两个贴心机制:自动重连和 Last-Event-ID。如果连接意外断开,浏览器会自动重新发起连接;服务器还可以通过 id: 字段告诉客户端“你断到哪了”,重连时客户端带上这个 ID,服务器就能从断点续传。这让 SSE 在弱网环境下依然有不错的鲁棒性——传送带断了,拼接好又继续转。
\text{SSE 消息} = \text{"data: " + 内容 + "\n\n"}- `data` 前缀:标记这行是消息内容的字段名,类似传送带上的碟子底部印着的“三文鱼”标签。
- 空行
\n\n表示消息结束的分隔符,服务器发完一条消息后必须跟一个空行,浏览器才认为“这条消息完整了”。\text{"\n\n"} - 流式传输连接不是一次性关闭的,服务器可以持续发送多条
data: 内容\n\n,如同传送带不断上菜。
data: 你好SSE 与 WebSocket 对比
选通信协议,有点像选择用餐方式:如果你只是坐在吧台前等主厨一道道把菜递给你,SSE 的“单向传送带”绰绰有余;但如果你需要跟主厨讨论“这道菜少放盐、那道菜多加点芥末”,就需要一种双向对话机制——这正是 WebSocket 的用武之地,它是一条允许双方随时往对方盘子里夹菜的双向通道。
先说协议层面。WebSocket 是一个独立的协议(ws:// 和 wss://),它需要在 HTTP 之上进行一次“升级握手”,把协议从 HTTP 切换为 WebSocket 协议。而 SSE 本质还是 HTTP——它没有协议升级,只是把连接的响应方式从“一次性”变成了“持续推送”。这个差异带来一个关键后果:SSE 天然兼容现有的 HTTP 基础设施(比如负载均衡、防火墙通常都放行 HTTP),而 WebSocket 在某些代理环境里可能会被拦。
再说通信模式。WebSocket 是双向的,客户端和服务器都可以随时发起消息;SSE 是单向的,只能服务器向客户端推。这带来一个微妙的工程权衡:SSE 的模型极简——你不需要处理来自客户端的随时消息,少了一整类并发问题。但代价是:如果你的应用场景需要客户端频繁向服务器发消息(比如多人实时协作编辑器),SSE 就得再开一个普通 HTTP 通道配合使用,绕了一个弯。
WebSocket 就像一个高级的双方对讲机,什么都好,但你要是用它来单向喊话,就杀鸡用了牛刀。SSE 用最小的机制做最合适的事——对 LLM 应用而言,模型生成回答本来就是单向的,SSE 是性价比最高的选择。
- 单向性得分大模型对话只需要服务器向客户端推流,SSE 在“单向够用”这个维度上打高分。
- 复杂度得分SSE 无需协议升级、无需心跳包(HTTP 层自动处理),工程复杂度远低于 WebSocket。
- 兼容性得分SSE 走标准 HTTP 端口,能穿透绝大多数企业代理,浏览器的
EventSourceAPI 内置自动重连。
Python 实现 SSE 接口
纸上谈兵容易,真正的问题来了:怎么在你的 Python 后端里端出这条传送带?现代 Web 框架几乎都支持 SSE。这里我们用 FastAPI 来演示——它原生支持异步流式响应,语法异常简洁。FastAPI 是一个基于 Python 类型注解的现代 Web 框架,相当于餐厅的中央厨房管理系统,你只需要告诉它“这道菜走传送带上”。
SSE 的原理不复杂,实现也谈不上尖端,但真正的难点在于正确设置响应头和用生成器产出数据。核心点:生成器是一种惰性求值的函数对象——普通函数是一次性把所有结果算完返回,而生成器一次只产出(yield)一个值,然后暂停。当你在生成器里循环遍历大模型的输出时,每个 yield 都会立即把内容推送到客户端,这就是 SSE 流式的魔法所在。
服务端代码的核心骨架如下:定义一个生成器函数,在循环中 yield 出符合 SSE 格式的字符串(即 data: ...\n\n),然后用 StreamingResponse 包装给 FastAPI——这个类就像一个贴好标签的传菜窗口,它知道要用 text/event-stream 来标识这次响应。客户端收到这个响应头后,就知道“这条连接会持续上菜,不会等一次送完”。
就这么简单——SSE 接口的实现本质是一个生成器 + 一个响应头。但要注意,这只是“能用”的起点。实际生产环境还需要处理客户端断开、代理缓冲、并发控制等问题,这些在后面的章节展开。先把这个骨架搭出来跑通,再持续加固。
- 生成器一个产出 token 的迭代器,每次
yield出一个 token,相当于传送带每次放一个寿司上去。 text/event-stream响应头告诉客户端“这是 SSE 流”,浏览器或前端框架据此解析消息边界而非直接关闭连接。- StreamingResponse框架提供的响应包装器,接收生成器对象,在连接不断开的前提下持续发送数据。
SSE 在 LLM 应用实战
现在你已经掌握了传送带的原理,是时候看看它在真实餐厅里的运转了。最经典的场景当然是大模型对话应用——ChaiGPT、Claude、文心一言的网页界面,你输入一句话后看到的逐字输出,底层几乎都是 SSE 在发力。这条传送带从 Llama 或 GPT 模型推理服务开始,把一个个 token(最小文本单位)传送到你的浏览器上。
具体流程拆解:前端用 EventSource 或 fetch 的流式模式发起请求;后端收到请求后向 LLM 推理服务发出调用,两者之间通常也走 SSE;后端拿到模型的 token 流后,用生成器逐字取出内容,再以 SSE 格式转发给前端——这就像传送带在中转站接驳,一路直达用户。前端每收到一条 data: 消息,就追加一段文字到页面上,于是用户看到的就是“AI 在思考中打字”。
SSE 的另一个实用战场是实时进度上报。想象你有一个“文章摘要批处理系统”,用户提交 100 篇文档,系统要逐一处理。传统做法是提交后页面上一个进度条旋转半天;用 SSE,服务器每处理完一篇文档就推送一条进度消息,前端实时更新百分比,用户体验瞬间提升一个档次。这种用法不需要大模型,但 SSE 的单向推送特性在这里恰如其分。
掌握了这条链路,你就能自己动手做一个和大厂体验相当的 AI 对话应用了。传送带就是消息通道,LLM 就是主厨,而你要做的就是把两者接得溜光顺滑。
- 用户输入到后端前端将用户的问题通过普通 HTTP POST 发送给后端。
- 后端转发给 LLM后端将对话历史拼接成 Prompt,转发给推理服务器(如 vLLM 或 OpenAI API)。
- LLM 流式生成推理服务器开启
stream=true,按 token 产出内容。 - SSE 逐字推送后端把每个 token 包装成 SSE 消息推给浏览器。
\text{data: token}_n \text{\n\n} \rightarrow \text{浏览器}
SSE 局限与最佳实践
传送带也不是万能的。如果有一天客人想跟主厨实时对话、调整口味,单向的传送带就乏力了——因为 SSE 只能从服务器到客户端单向流动,客户端无法通过同一条连接给服务器发消息。这意味着你不能用 SSE 做聊天室、多人协作白板这类需要双向高频交互的应用。要双向,还是得用 WebSocket,别硬用 SSE。
另一个隐蔽的坑在网络代理的缓冲问题。很多企业级代理/Nginx 默认会缓冲 HTTP 响应,等积累到一定量才转发给客户端——这在普通响应时没问题,但对 SSE 来说,等于传送带被中间人囤货了,前端迟迟收到不到 data 消息。解决方法是在 Nginx 中显式关闭缓冲:proxy_buffering off;。这提醒我们:SSE 依赖“边生成边推送”,任何环节的缓冲都可能导致体验毁于一旦。
最后,说一下断线重连策略和心跳机制。浏览器 EventSource 自带自动重连,但服务器端需要配合:客户端重连时,服务器应该知道它断到了哪条消息,这靠 SSE 的 id: 字段实现。同时,如果连接长期空闲(比如大模型在思考),某些中间设备可能把空闲连接当废连接掐掉,所以需要给连接发送心跳注释(:\n\n),告诉代理“我还在活着呢”。这跟寿司师傅为防止客人离席,时不时往传送带上放一碟姜片传递“营业中”信号是一个道理。
要在生产环境用好 SSE,核心原则就是尊重传输路径上的每一个环节。代理要关缓冲,负载均衡要支持长连接超时配置,服务端要发心跳;只有把这些螺丝都拧紧,传送带才能昼夜不息地旋转。
- 周期心跳服务端每隔 15-30 秒发送一条注释帧,维持连接活跃。
\text{:\n\n} - 断线续传客户端重连时携带
Last-Event-ID,服务端据此跳过已发送的消息。 - 代理透传关闭反向代理的响应缓冲,确保数据立刻直达客户端。
AI 应用场景
场景一:大模型对话应用的逐字输出
阶段:模型推理与服务部署
解决的问题:大模型生成完整回答需要 5-15 秒,传统同步 HTTP 接口让用户长时间面对空白页面。用户被迫在“等待完成”的焦虑中煎熬,极易误以为服务已崩溃。SSE 流式接口将模型输出的 token 实时推送,用户只需等待 0.5 秒就看到第一个字,完整回答分秒之间就位,交互体验越趋近于人与人的即时对话。
具体案例:某客服机器人团队在将大模型接入网页端时,最初使用同步 HTTP 接口,用户反馈“页面像卡死了”。改用 SSE 流式响应后,回答逐字显示,用户等待焦虑大幅缓解,任务完成率提升 31%。实现中后端用 FastAPI 的 StreamingResponse 包装生成器函数,前端使用 fetch API 的 stream 模式读取数据,一行行解析、追加到对话气泡中。
场景二:AI 文档处理任务的实时进度上报
阶段:数据处理与任务编排
解决的问题:在批量处理任务(如文档解析、语音转写、批量润色)中,任务可能耗时数十秒甚至数分钟。传统做法是前端不断轮询任务状态接口,既浪费请求资源,又无法反馈细粒度进度。SSE 单向推送机制恰好匹配“服务器主动上报状态”的需求。
具体案例:某知识库系统管理员上传 50 份 PDF 进行向量化入库,后端通过 SSE 在每完成一份文档时推送一条进度消息(如 data: {"completed": 12, "total": 50}),前端实时渲染进度条,并在所有任务完成时推送 data: {"status": "done"} 触发页面跳转。相比轮询方案,后端请求量降低了 90%。
Python 演示
import jsonimport timefrom fastapi import FastAPIfrom fastapi.responses import StreamingResponse app = FastAPI() def mock_llm_stream(prompt: str): """模拟大模型流式生成, 按 token 逐个产出回答片段""" full_answer = f"你好, 你刚才问的是: {prompt}。让我为你详细解答..." for char in full_answer: time.sleep(0.05) # 模拟 50ms 生成一个字 yield char def format_sse(data: str) -> str: """将数据封装成 SSE 格式""" return f"data: {data}\n\n" @app.get("/chat/stream")def chat_stream(prompt: str): """SSE 流式对话接口""" generator = mock_llm_stream(prompt) def event_stream(): for chunk in generator: payload = json.dumps({"token": chunk}, ensure_ascii=False) yield format_sse(payload) return StreamingResponse( event_stream(), media_type="text/event-stream", headers={ "Cache-Control": "no-cache", "Connection": "keep-alive", "X-Accel-Buffering": "no", }, ) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
/chat/stream?prompt=你好 时,服务端按字逐字推送响应,模拟大模型的打字机效果。mock_llm_stream(prompt)模拟大模型推理输出流,先拼出完整句子再用time.sleep(0.05)逐字吐出,真实场景中这里是调用 vLLM/OpenAI 的流式接口。format_sse(data)SSE 格式的封装函数,核心是data: 内容\n\n格式。这是整个协议的字面核心,前端依赖空行识别一条完整消息。event_stream()逐字取出生成器内容,包装为 JSON 格式后按 SSE 格式产出。StreamingResponse(...)FastAPI 的关键封装:接收生成器对象并保持 HTTP 连接不断开,返回流式响应。media_type="text/event-stream"设置 SSE 特有的 MIME 类型,浏览器和前端库据此知道该用流式方式解析。"Cache-Control": "no-cache"禁用缓存,防止代理或浏览器缓存 SSE 响应导致数据延误。"X-Accel-Buffering": "no"专门针对 Nginx 的响应头,关闭代理缓冲,让数据立即传送,不被囤积。
常见误区
误区既然 SSE 是一条“连接”,那客户端应该也能通过它向服务器发送数据吧?就像 WebSocket 一样,来回传递消息。
正解SSE 是单向通道,数据只能从服务器流向客户端。在浏览器中,EventSource API 根本没有提供向服务器发送消息的方法。如果需要双向通信,WebSocket 才是正确的工具——这就好比传送带的设计目标是把菜从厨房送到客人的面前,而不是让客人把菜传回厨房。
为何常见:很多人看到“持久连接”就自动脑补出“双向会话”,因为市面上主流的持久连接方案(WebSocket、Socket.IO)几乎都是双向的,容易以偏概全。
误区SSE 应该是像 WebSocket 一样的新传输协议,需要专用的服务器、专用的端口和复杂的握手流程才能使用。
正解SSE 不是新协议,它仍然构建在普通 HTTP 之上,只是通过 Content-Type: text/event-stream 响应头和 Transfer-Encoding: chunked 或逐块刷新机制,让连接在响应完成后继续存活。这意味着任何支持 HTTP 的服务器都能实现 SSE,不需要升级到新协议栈,防火墙和代理通常也无需额外放行。它就像走的还是普通马路,只是司机不停车而已。
为何常见:WebSocket 的“升级协议”概念太深入人心,导致人们想当然地认为所有实时通信方案都要有新协议。
误区既然 SSE 消息格式是 `data: 文本`,那它一定只能传纯文本,不能传 JSON 或二进制数据。
正解SSE 的 data: 字段里穿什么内容完全由你决定。实际生产中,最常见的做法恰恰是把 JSON 序列化成字符串放在 data: 后传输——比如 data: {"token":"你", "index":0}。只要在服务端序列化、在客户端解析,就能传递结构化数据。二进制内容可以转成 Base64 编码再传,只是传输效率不如 WebSocket 的原生二进制帧。把它想成传送带上的餐盒,里面装生鱼片你可以把盒盖打开直接吃,但你不影响装便当盒里还有米饭和味噌汤。
为何常见:看到“文本/事件流”(text/event-stream)就陷入字面理解的误区,忽略了底层可以承载任意序列化数据的事实。
误区SSE 的持久连接既然一直不关闭,那它肯定比普通请求更消耗服务器资源,连接数一多服务器就垮了。
正解SSE 连接确实长期占用,但一个空闲的 SSE 连接几乎不消耗 CPU,只保留一个 socket 文件描述符和少量内存。相比 WebSocket 需要维护双向心跳和额外状态,SSE 在空闲时的开销更低。现代服务器(如 Nginx 或 Go)处理十万级并发连接早已是常态。真正需要关注的是代理服务器的连接数限制,而不是连接本身的成本。
为何常见:把“长连接”和“高资源消耗”划等号——对网络编程不熟悉的人容易高估 socket 占用的成本。
面试题
Q1. SSE 的全称和核心特征是什么?
- A.Server-Sent Events,基于 HTTP 的单向服务器推送协议← 正确答案
- B.Server-Socket Events,基于 TCP 的双向通信协议
- C.Standard-Sent Events,基于 UDP 的广播协议
- D.Stream-Socket Events,基于 WebSocket 的推送协议
答案:A。SSE 是 Server-Sent Events 的缩写,它仍然基于标准 HTTP 协议,数据流只能从服务器流向客户端。B 提到“双向”与 SSE 本质矛盾;C 错在 UDP——SSE 是 TCP 之上的 HTTP;D 错在把 SSE 和 WebSocket 混为一谈,两者是完全不同的机制。
Q2. SSE 消息的标准格式是什么?
- A.
data: 内容\n(单换行结尾) - B.
data: 内容\n\n(双换行结尾)← 正确答案 - C.
stream: 内容\n\n - D.
push: 内容\n\n
答案:B。SSE 规范规定消息字段以单换行结束,消息之间用空行(即双换行)分隔。data: 内容\n\n 是标准的单条消息格式,前面的 \n 是字段行结束符,后面的 \n 是消息结束的空行标记。A 少了空行标记,C 和 D 字段名错误——SSE 没有 stream: 或 push: 字段。
Q3. SSE 默认使用哪种 MIME 类型标识流式响应?
- A.
application/json - B.
text/plain - C.
text/event-stream← 正确答案 - D.
application/octet-stream
答案:C。这是 SSE 的标识性特征。服务器必须把 Content-Type 设置为 text/event-stream,浏览器才能识别这是 SSE 连接并按事件流格式解析。application/json 是普通 JSON 响应,text/plain 是纯文本,application/octet-stream 是二进制流——三者都是普通一次性响应。
Q4. SSE 与 WebSocket 相比,最大的结构性区别是什么?
- A.SSE 基于 UDP,WebSocket 基于 TCP
- B.SSE 是单向的,WebSocket 是双向的← 正确答案
- C.SSE 只支持二进制数据,WebSocket 只支持文本数据
- D.SSE 必须使用多个连接,WebSocket 只能使用一个
答案:B。SSE 是服务器到客户端的单向通道,WebSocket 则允许客户端和服务器双向收发消息。A 错误——两者都基于 TCP;C 错误——SSE 传文本为主但可封装 JSON 字符串,WebSocket 两者都支持;D 错误——SSE 只需一个连接,逻辑上反向消息通过普通 HTTP 另发。
Q5. 在浏览器中接收 SSE 事件流,最合适的原生 API 是什么?
- A.
WebSocket - B.
fetch+ 手动解析流 - C.
XMLHttpRequest - D.
EventSource← 正确答案
答案:D。EventSource 是浏览器原生提供、专为 SSE 设计的 API,它内置了连接管理、自动重连、消息事件派发等功能。WebSocket 是另一套协议和 API;fetch 的 stream 模式需要手动处理 SSE 格式,是备选方案(服务端代理场景常用);XMLHttpRequest 对长连接支持差,不是正确选项。
Q6. 下列哪些场景适合使用 SSE 而不是 WebSocket?
- A.大模型对话应用逐字输出回答← 正确答案
- B.实时双向联机游戏(如多人棋牌)
- C.服务器向客户端推送实时进度通知← 正确答案
- D.视频通话的音视频双向传输
答案:AC。SSE 适合“服务器单方面持续推数据”的场景。大模型输出(A)和进度上报(C)都是典型单向推送,SSE 足够且更轻。B 和 D 需要客户端和服务器高频双向交互——联机游戏要同步双方操作,视频通话要双向传音视频流,这些必须用 WebSocket 或其他实时双向协议。
Q7. 服务端用 FastAPI 实现 SSE 流式响应时,哪个关键步骤是必须的?
- A.使用
WebSocket装饰器路由 - B.使用生成器逐块产出内容,并设置
media_type="text/event-stream"← 正确答案 - C.设置
Content-Encoding: gzip压缩头 - D.设置
Accept-Encoding请求头
答案:B。FastAPI 的 StreamingResponse 接收生成器对象并持续输出,配合 media_type="text/event-stream" 让响应变为 SSE 流。A 是 WebSocket 的实现方式;C 的 gzip 在流式场景反而会因缓冲破坏实时性;D 是请求头不是响应头,不在此处设置。
Q8. SSE 连接的自动重连特性,主要依赖浏览器端的什么机制?
- A.
setInterval定时器主动轮询服务器 - B.
EventSourceAPI 对断连的自动重试← 正确答案 - C.HTTP 协议本身的重传机制
- D.用户手动刷新页面
答案:B。EventSource 内置了连接中断后自动重新建立连接的能力,重试间隔约 2-3 秒(可配置),无需开发者额外编写重连逻辑。A 是轮询方案,不是 SSE 的机制;C 的 HTTP 重传只针对普通响应,不覆盖连接中断后的重新建立;D 把体验交给用户,不符合“内置重连”的特性。
Q9. SSE 在实际部署中可能遇到哪些坑?
- A.Nginx 等反向代理缓冲导致数据延迟送达← 正确答案
- B.连接空闲超时被中间设备掐断← 正确答案
- C.代理缓存错误造成客户端收到旧数据← 正确答案
- D.SSE 消息格式错误导致客户端无法解析← 正确答案
答案:ABCD。这四个都是真实的部署问题。A 需设置 proxy_buffering off 关闭缓冲;B 需通过心跳注释保持连接活跃;C 需设置 Cache-Control: no-cache 并让所有中间代理不缓存响应;D 是协议层问题,必须保证每条消息以空行正确结尾,以及 data: 前缀的拼写无误。
Q10. SSE 的 id: 字段在消息中的作用是什么?
- A.标记消息的发送时间
- B.标记消息的唯一标识,用于断线重连时续传← 正确答案
- C.标记消息的优先级
- D.标记消息的语言种类
答案:B。id: 字段给消息分配唯一标识。连接断开后,EventSource 重连时会自动带上 Last-Event-ID 请求头,服务器据此判断客户端已经收到哪条消息,从下一条继续发送。这个设计和断点续传的机制密切相关,是 SSE 在弱网环境下保持可靠性的关键工具。