想象你正在策划两档节目:一档是「AI 助手早间播报」广播电台,另一档是「多人连线热线」电话节目。 广播电台的工作方式很简单——主播(服务器)在直播间对着话筒不断输出,听众(客户端)只需要调准频道、安静收听。信息永远从电台单向流向听众,听众不需要说话。如果信号偶尔中断,智能收音机会自动重新搜索频道、接着播放,听众几乎无感知。 电话节目则完全不同——主持人、嘉宾、场外观众都能随时开口,每个人既在听也在说,这是一场真正的「双向对话」。但电话接通需要专门拨号、建立线路,断线了还得自己重拨,没人替你做。 SSE(Server-Sent Events,服务器发送事件)就是那台智能收音机——基于 HTTP 的服务器单向推送技术;WebSocket 就是那条电话线——基于 TCP 的全双工通信协议。今天这篇选型指南,就是帮你判断:你的 AI 服务到底该开一档广播,还是打一通电话?
掌握 SSE 与 WebSocket 的选型能力,是设计高吞吐流式 API 的核心技能,直接决定 AI 产品实时体验的架构路线上限。
可视化演示
直观对比SSE单向推送和WebSocket双向通信的架构差异,帮助AI服务架构师选择合适的流式API通信方案。
本节配有交互动效(进入视口后自动加载,约 3KB)。
SSE:单向流式推送 服务端→客户端单向推送,基于HTTP协议,实现简单 适合LLM流式输出、实时通知等单向数据场景 SSE是AI流式API的首选方案
通信模式对比
广播和电话最本质的区别,是听众的声音能不能传回直播间。你在开车时听电台,无论你怎么喊,主持人永远听不见;而打电话时,双方都能随时插话、相互回应。SSE 与 WebSocket 的第一个分水岭,恰恰就划在这条数据流方向上。
SSE 是一条单向管道,术语叫单工通信。服务器把 HTTP 响应体当作一条永不关闭的送水管道,消息从服务器端源源不断流出,浏览器用 EventSource 对象在另一端接水。这条管道上只有「服务器写、客户端读」一个方向,客户端若想反向发消息,只能另开一个普通的 HTTP 请求。
WebSocket 则是一条真正的全双工通道。连接建立之后,两端各自持有收发两用的消息帧接口,服务器和客户端可以同时发消息、互不排队、互不阻塞。聊天、白板、游戏操作这类「两边都频繁说话」的场景,只有全双工才自然。
选广播还是电话,先问自己:听众需不需要在收听时插话?如果你的 AI 产品只是「播音员」单向输出,广播天生更省力;只有需要实时对话时才值得拉起一条电话线。
- SSE 方向标记箭头永远从 Server 指向 Client,表示消息无法在连接上反向流动,客户端要回话必须另外发请求。
- WebSocket 双向标记上下两条箭头同时存在,表示同一条连接内双向车道实时通行,任何一端都能随时发消息。
协议底层机制
广播电台用的是国家统一规划的公共频段,听众手里的收音机不用做任何改装就能接收;而打电话必须从运营商那里专门拉一条线路,从交换机一路连通到对方家里。SSE 和 WebSocket 在协议层面也体现了同样的「复用」与「新建」之别。
SSE 跑在普通 HTTP 之上。客户端发一个 GET 请求,服务器不在响应体结束时断掉连接,而是持续向响应体里写入文本片段。由于它本质就是 HTTP,Nginx、CDN、负载均衡、防火墙这些基础设施天然认识它,几乎零改造就能穿透复杂网络。
WebSocket 则是独立的协议。客户端先发一个带上 Upgrade: websocket 头部的 HTTP GET 请求,服务器返回 101 Switching Protocols 状态码后,这条 TCP 连接才从 HTTP 切换到 WebSocket 帧协议。中间每一层代理都必须显式支持 Upgrade 跳板,否则连接会被拦在半路。
广播不用改造收音机频道,电话却需要从头到尾把线路打通。SSE 对 HTTP 基础设施的「亲和力」,在代理防火墙林立的企业级网络环境中,是常常被低估的隐形优势。
- 握手请求客户端用普通 GET 请求发起,头部携带 Upgrade: websocket 声明「我想切换协议」。
- 切换响应服务器返回 101 Switching Protocols,表示「同意换线」,此后连接按 WebSocket 帧格式通信。
连接维护策略
收音机一旦信号变差,会自动重新搜索频道、继续播放刚才的节目;而电话断线后,你必须自己记起电话号码、手动重拨。这两种「断线体验」的差异,恰好对应 SSE 与 WebSocket 在连接维护上的默认行为。
EventSource 天然内置断线重连机制。连接意外断开后,浏览器会自动重新发起 GET 请求,并且能携带 Last-Event-ID 响应头,告诉服务器「你刚才播到哪一条了,从这里继续补播」。AI 流式输出中断后自动续传,几乎零代码白拿。
WebSocket 则没有任何自动重连能力。断线后浏览器只触发一个 close 事件,重试间隔怎么定、上次消息从哪条继续、要不要缓存未发消息,全部需要你自己实现。这些「隐藏工程量」在方案评审时经常被忽略,上线后才发现要写一整套连接管理器。
SSE 自带「搜台续播」的省心能力,对 AI 流式输出这种单次连接可能持续数十秒甚至数分钟的场景尤其宝贵。WebSocket 虽然强大,但断线重连这笔账,迟早要还。
- 重试次数n 是第几次重连尝试,t0 是初始等待时间。
- 指数增长重试次数越多,等待时间按 2 的幂次增长,避免重连风暴。
- 封顶保护等待时间超过 tmax 后不再增长,保证连接恢复后能及时重连。
数据格式差异
广播字幕是一行一行往下滚的文字,格式固定、谁都能读;电话则既能说人话,也能传入传真、图片、音频等各种文件。SSE 与 WebSocket 在「讲什么语言、能传什么货」上也分道扬镳。
SSE 只能传输 UTF-8 文本。每条事件以 data: 开头、以空行 \n\n 结尾,中间可以用 event: 指定事件名、用 id: 指定消息序号。因为它是纯文本流,任何 HTTP 代理、日志系统、抓包工具都能直接读懂内容,排查问题非常直观。若要传二进制数据,只能 base64 编码,体积膨胀约 33%。
WebSocket 支持文本帧和二进制帧两种消息类型。通信双方可以直接交换 ArrayBuffer、Blob 等二进制数据,不需要任何编码转换。对音频 PCM 帧、图像块、游戏状态快照这类数据,WebSocket 的原生二进制能力省下了大量编码开销。
广播只放送文字,电话能传文件。如果你的 AI 流式返回只是 JSON 文本片段,SSE 足够且更直观;如果要推音频流或图像块,WebSocket 的二进制帧才是主场。
- 类型行event 字段标注本条事件类型,对应浏览器分发的自定义事件名。
- 数据行data 字段携带实际内容,多条 data: 行会按顺序合并成一条消息。
- 分隔符连续两个换行代表一条事件结束,浏览器据此切分事件流。
浏览器兼容性
收音机几乎是家家户户的标配;电话早年在大山深处信号不佳,但随着基站铺开,覆盖率已经很高。SSE 与 WebSocket 在浏览器端的支持度,也呈现出「略逊但够用」与「全面覆盖」的微妙差距。
EventSource 的兼容性「差一点但不是大问题」:IE 全家和旧版 Edge 不支持,其余主流浏览器(Chrome、Firefox、Safari、新版 Edge)全部原生支持。如果产品必须兼容 IE 时代的老旧终端,官方有成熟的 polyfill 方案可以补上能力。
WebSocket 则几乎所有浏览器都原生支持,包括早期移动端浏览器。作为实时 Web 的底层基建协议,它的覆盖范围接近全网。但注意,「支持连接」不等于「支持稳定连接」——公司内网代理可能拦截 Upgrade 请求,这在兼容性评估中经常被忽略。
收音机基本每家都有,电话也几乎全覆盖。兼容性这一维度,两边都够用,不构成决定性差异——除非你的用户群体偏偏集中在老旧浏览器上。
- SSE 支持率约 95% 的浏览器环境原生支持 EventSource,缺口集中在 IE 与旧版 Edge。
- WebSocket 支持率约 97% 的环境原生支持,覆盖更早更广。
- 差距本质几个百分点的差异可通过 polyfill 弥合,真正的卡点往往是企业代理而非浏览器。
典型应用场景
什么时候开广播,什么时候打电话?生活经验早就给了答案:路况播报、天气预警、新闻联播——单向通知用广播;热线聊天、多人会议、远程协作——互动沟通用电话。AI 服务的场景选择,遵循同样的逻辑。
SSE 的主场是「高频单向通知 + 长耗时流式输出」。大模型 token 逐个滚出的打字机效果、Agent 执行日志的流式上报、股票行情推送、新闻瀑布流,这些场景中 90% 以上的消息都从服务器流向客户端。SSE 用一个 HTTP 连接 + 自动重连就全部搞定,连接数省、代码量省、运维负担也轻。
WebSocket 的主场是「低延迟双向交互」。即时聊天、多人白板、云游戏、实时协同编辑、IoT 设备控制,客户端要频繁发指令,服务器要实时回推状态。这时只有双向车道能承载「你一句我一句」的密集对话,SSE 的「另开 POST 请求」模式会显得笨重且延迟更高。
AI 聊天机器人的「打字机字幕」是典型广播场景;但如果你做的是「AI 协同画布」,服务器和用户都要实时改动图形,就得拿起电话。先区分场景,再谈选型。
- 单向主导分支绝大多数数据由服务器喷出,SSE 的连接成本与实现复杂度最低。
- 双向主导分支客户端也频繁发送,必须升级到 WebSocket 双向通道。
选型决策框架
到了拍板环节,就像给家里选购通信套餐:把需求一条条列出来,对着清单打勾,而不是听销售吹得天花乱坠。SSE 与 WebSocket 的选型也可以固化为四个步骤的决策框架。
第一步看数据流向:消息 90% 单向流动,直接选 SSE;双向高频交互,选 WebSocket。第二步看消息形态:纯 JSON 文本流,SSE 够用;需要传输二进制音频、图像、自定义帧,WebSocket 更顺手。第三步看连接规模:广播场景动辄上万并发连接,WebSocket 长连接吃内存、占文件描述符更多,架构复杂度更高;SSE 借助 HTTP/2 还能多路复用。第四步看基础设施:SSE 是 HTTP,代理和防火墙天然放行;WebSocket 要求全链路代理支持 Upgrade,改造周期不可低估。
把四个维度量化,可以得到一个加权评分模型:
其中 $b$ 为双向需求度(0-1),$f$ 为二进制需求度(0-1),$c$ 为基建复杂度成本(0-1),$w_1,w_2,w_3$ 为对应权重。
没有最好的通信协议,只有最适配的对话方式。绝大多数 AI 流式 API 用广播(SSE)就已超额完成任务,省下的复杂度就是团队最宝贵的时间。
- 双向需求分b 越大越是聊天协作类场景,WebSocket 加分越多。
- 二进制需求分f 高说明要传音频视频,WebSocket 原生优势转化为分数。
- 复杂度扣分c 来自代理改造、重连自研、运维成本,从总分中扣除。
- 决策比较SSE 可视为基准分 1,WebSocket 只有当净收益显著大于 1 时才值得切换。
AI 应用场景
大模型流式对话接口(SSE 广播台)
阶段:LLM 推理输出与在线服务部署
解决的问题:传统方式等模型全部推理完再一次性返回,用户看到首个字往往要等好几秒,体验笨重。AI 方式下,SSE 让服务器把 token 逐个「播报」给客户端,首 token 延迟降低到几百毫秒,配合打字机渲染,对话体验丝滑自然。
具体案例:某 AI 客服产品将后端对话接口改为 text/event-stream,用户在提问后约 0.3 秒就看到第一个字开始滚动,整体感知速度提升了近 5 倍。断网时浏览器自动重连并携带 Last-Event-ID,漏掉的回复片段由服务端补发。
多人在线协同白板(WebSocket 电话线)
阶段:实时协同编辑与状态同步
解决的问题:AI 设计助手与多名人类设计师共享一块画布,每个人拖拽图形、修改标注,动作都要实时同步给所有人。SSE 的单向管道无法承载客户端高频的图形指令,WebSocket 的双向通道让每次拖动都像电话里的即时对话。
具体案例:某 AI 设计工具团队用 WebSocket 实现画布状态同步,服务端维护房间连接池,将 AI 生成的设计草图和用户的手动调整都以二进制帧广播,多人协同时延稳定在 50ms 以内。
金融行情推送平台(SSE 播报员)
阶段:行情数据管道与推送服务
解决的问题:股票行情天然是「交易所 → 平台 → 用户」的单向瀑布流,客户端不需要向服务器发任何行情数据。用 WebSocket 纯属大材小用,还带来连接维护和重连自研的额外成本。SSE 以近乎零成本的方式实现每秒多档行情推送。
具体案例:某量化行情平台用 SSE 向数千客户端推送沪深 Level-1 行情,服务端只需维护简单的 HTTP 连接池,配合 Kafka 消费行情后直接写入响应流,单机支撑 5 万并发连接,故障时自动重连自动续推。
Python 演示
"""Compare SSE and WebSocket for streaming AI responses."""import jsonimport timefrom http.server import BaseHTTPRequestHandler, HTTPServerfrom urllib.parse import urlparse def token_generator(text): """Yield each character of text with a small delay.""" for char in text: yield char time.sleep(0.05) class SSEHandler(BaseHTTPRequestHandler): """Demo server: SSE streaming plus a simple client-to-server POST.""" def do_GET(self): if urlparse(self.path).path != "/stream": self.send_response(404) self.end_headers() return self.send_response(200) self.send_header("Content-Type", "text/event-stream") self.send_header("Cache-Control", "no-cache") self.send_header("Connection", "keep-alive") self.end_headers() reply = "Hello from AI streaming server!" for token in token_generator(reply): payload = "data: " + json.dumps({"token": token}) + "\n\n" self.wfile.write(payload.encode("utf-8")) self.wfile.flush() def do_POST(self): if urlparse(self.path).path != "/chat": self.send_response(404) self.end_headers() return length = int(self.headers.get("Content-Length", 0)) body = json.loads(self.rfile.read(length) or b"{}") self.send_response(200) self.send_header("Content-Type", "application/json") self.end_headers() echo = {"echo": body.get("message", "")} self.wfile.write(json.dumps(echo).encode("utf-8")) def log_message(self, fmt, *args): print("[server] " + (fmt % args)) def main(): server = HTTPServer(("localhost", 8765), SSEHandler) print("SSE server running at http://localhost:8765/stream") try: server.serve_forever() except KeyboardInterrupt: server.shutdown() if __name__ == "__main__": main()
self.send_header("Content-Type", "text/event-stream")设置响应类型为事件流,浏览器收到后才知道这是 SSE 长连接。self.send_header("Cache-Control", "no-cache")禁止代理和浏览器缓存流式内容,保证每条消息实时到达。self.end_headers()结束响应头并保持连接不断开,后续写入的内容都作为响应体持续输出。payload = "data: " + json.dumps({"token": token}) + "\n\n"按 SSE 协议拼装数据帧,data 前缀加空行结尾,浏览器自动解析。self.wfile.flush()立即刷新缓冲区,让 token 以毫秒级延迟到达客户端,而不是攒一批再发。def do_GET(self)GET 请求建立 SSE 流;客户端发消息则走 do_POST,两个通道各自独立,正是「广播 + 另发信件」的组合。
常见误区
误区很多人一看到「服务器发送事件」这个名词,就断定 SSE 是单向的,客户端想发消息给 AI 只能换 WebSocket。实际上我在面试中也常遇到候选人大谈 WebSocket 的必要性,却不知道 SSE 早已支撑起无数对话产品。
正解SSE 指的是「服务器 → 客户端」这条长连接方向是单向的,但客户端完全可以通过额外的普通 HTTP POST 请求把消息发给服务器(也就是上一节 Python 演示里 do_POST 的角色)。服务端收到消息后,在原来的 SSE 流里把 AI 回复推回去。对话系统用「POST 进、SSE 出」的架构,正是目前大模型应用的主流方案。
为何常见:因为「单向」这个定语太容易被理解为「整个系统只能有一个方向」,而忽略了 HTTP 请求-响应模型里客户端天然的发送能力。
误区不少开发者默认 WebSocket 和 SSE 一样,断开后浏览器会自动重连,所以选型时觉得 WebSocket 更强大又免维护,一头扎进去。
正解恰恰相反。SSE 的 EventSource 从设计之初就内置了断线重连和 Last-Event-ID 续传机制,而 WebSocket 在断线后只抛一个 close 事件,重连间隔、退避策略、消息补偿全部要开发者自己实现。选 WebSocket 意味着你要额外维护一套连接状态机,这是最常见的隐性成本。
为何常见:人们容易把「连接稳定」想成协议层的默认职责,但这个世界上没有免费的自动重连——SSE 把重连做进了标准,而 WebSocket 把选择权留给了你。
误区看到 SSE 只支持 UTF-8 文本,就认为它无法胜任现代多媒体场景,觉得凡是涉及二进制就必须上 WebSocket。
正解SSE 确实不原生支持二进制帧,但可以通过 base64 编码把任何二进制数据塞进 data 字段,通用性完全够。虽然体积膨胀约 33%,对带宽敏感的场景确实吃亏,但大量 AI 流式场景传的是 JSON 片段,根本涉及不到二进制。而 WebSocket 的二进制优势真正发挥作用的是音频流、图像块等高频大体积场景。
为何常见:人们容易从「不支持」直接跳到「不能用」,而忽略了 base64 这个无处不在的编码桥梁,也忽略了大多数业务其实根本不需要二进制。
误区潜意识里觉得 WebSocket 是「专用长连接」,SSE 是「普通 HTTP」,专用的一定更快,于是性能敏感场景无脑选 WebSocket。
正解在单条连接的端到端延迟上,两者并没有数量级差异。SSE 基于 HTTP/2 时还能多路复用,一条 TCP 连接承载多个推送流;而且 SSE 省去了握手的额外开销,首包到达时间往往更快。真正影响性能的是消息频率、序列化开销和服务端架构,而不是协议本身。WebSocket 的「快」更多体现在双向帧交换的灵活性上,并非绝对吞吐优势。
为何常见:人们习惯用「协议新旧」来判断性能强弱,但网络性能的瓶颈通常在于业务逻辑和系统架构,协议选型只是其中一个变量。
面试题
Q1. SSE 的全称是什么?
- A.Server-Sent Events← 正确答案
- B.Simple Stream Engine
- C.Socket Event Exchange
- D.Server-Side Encryption
答案:A。SSE 即 Server-Sent Events(服务器发送事件),是浏览器原生支持的服务端推送技术。B、C 是杜撰的组合词,D 是服务端加密的缩写混淆项。记住「服务器主动发送事件给客户端」这个语义就能锁定答案。
Q2. SSE 连接依赖于哪种底层协议?
- A.HTTP 长连接← 正确答案
- B.UDP 通信协议
- C.TCP 三次握手
- D.TLS 独立协商
答案:A。SSE 基于 HTTP 长连接实现,服务器在 HTTP 响应体中持续写入数据。UDP 是面向数据报的协议,TCP 三次握手只是建立连接的底层过程,TLS 独立协商则不是专门针对 SSE 的机制。
Q3. SSE 消息流中,数据行以哪个前缀开头?
- A.data:← 正确答案
- B.msg:
- C.text:
- D.info:
答案:A。SSE 标准规定每条数据必须以 data: 前缀开头,浏览器通过该前缀识别消息内容。msg:、text:、info: 都不是 SSE 协议的合法字段前缀,把帧格式记牢就能答对。
Q4. WebSocket 通过什么机制从 HTTP 升级为 WebSocket 协议?
- A.HTTP Upgrade 请求头← 正确答案
- B.TCP 端口重复绑定
- C.建立独立 UDP 通道
- D.DNS 协议重新协商
答案:A。WebSocket 握手依赖 HTTP 的 Upgrade: websocket 请求头,服务器返回 101 状态码后完成协议切换。B、C、D 都是捏造的升级方式;这是一道考查「先 HTTP 敲门、再切换协议」流程的标准题。
Q5. SSE 相比 WebSocket 的独特优势是哪个?
- A.浏览器内置自动重连← 正确答案
- B.支持二进制数据帧
- C.无需 HTTP 协议
- D.天然支持双向通信
答案:A。EventSource 内置断线自动重连和 Last-Event-ID 续传,这是 SSE 的招牌能力。二进制帧和双向通信恰恰是 WebSocket 的优势,SSE 必须基于 HTTP 才能工作,所以 C 也不对。
Q6. EventSource 要监听服务器发送的自定义事件,应该怎么做?
- A.使用 addEventListener 注册← 正确答案
- B.覆盖默认 onmessage 属性
- C.新建一个 custom 回调函数
- D.设置 HTML 事件标签属性
答案:A。服务器通过 event: customName 指定自定义事件名时,客户端必须用 addEventListener('customName', handler) 才能捕获。onmessage 只能处理默认 message 事件,C、D 是无效写法。这会区分「只背 API 名字」和「真正用过 EventSource」的候选人。
Q7. WebSocket 对象发送文本消息调用的方法是什么?
- A.send()← 正确答案
- B.write()
- C.post()
- D.push()
答案:A。WebSocket 实例通过 send(data) 方法发送消息,文本、ArrayBuffer、Blob 都走这个入口。write 是 Node 流的方法,post 是 HTTP 动词,push 是服务端推送相关概念,都不是 WebSocket API。
Q8. 下列场景中,更适合选择 SSE 的有哪些?
- A.AI 对话内容流式输出← 正确答案
- B.新闻资讯实时推送← 正确答案
- C.对战游戏操作同步
- D.在线白板多人协作
答案:AB。AI 流式输出和新闻推送都是「服务器单向喷数据」,SSE 连接轻量、自动重连,是理想选择。对战游戏操作同步和在线白板要求客户端频繁发指令、服务器实时回推,属于双向高频交互,必须用 WebSocket。
Q9. 相比 SSE,WebSocket 的技术优势包括哪些?
- A.真正的全双工对话← 正确答案
- B.原生支持二进制帧← 正确答案
- C.默认自动重连恢复
- D.内置消息持久化
答案:AB。WebSocket 是全双工协议且原生支持二进制帧,这是它相对 SSE 的两大核心优势。自动重连恰恰是 SSE 的特性而非 WebSocket 的内置能力,消息持久化两种协议都不提供,需要业务层自己实现。
Q10. 关于 SSE 与 WebSocket 的选型判断,正确的有哪些?
- A.SSE 可复用 HTTP 基础设施← 正确答案
- B.WebSocket 需自行实现重连← 正确答案
- C.SSE 适合高频单向推送← 正确答案
- D.WebSocket 仅支持文本数据
答案:ABC。SSE 跑在 HTTP 之上,可以穿透绝大多数代理和防火墙,基础设施复用成本低;WebSocket 断线后必须自己实现重连;高频单向推送正是 SSE 的主场。D 明显错误,WebSocket 支持文本和二进制两种帧。综合题考查的是对两种协议全貌的把握。