资讯详情

SSE 为什么不用 WebSocket?EventSource 不能带鉴权头怎么解决?

📅 2026/10/16 6:18:27 | 华诺云谱 👁 阅读
SSE 为什么不用 WebSocket?EventSource 不能带鉴权头怎么解决?
前言在 AI 大模型流式对话、实时通知、股票行情等场景中服务端需要持续向客户端推送数据。这时候摆在你面前的有两条路WebSocket和SSEServer-Sent Events。很多人的第一反应是“上 WebSocket 吧功能强双向通信”——结果杀鸡用了牛刀服务端多了一套协议栈运维多了一堆配置。而当你决定用更轻量的 SSE 时又撞上了另一个墙EventSourceAPI 不能带自定义请求头Authorization 头死活加不上去JWT Token 无处安放。本文将从两个问题出发深入剖析 SSE 的技术定位、与 WebSocket 的本质差异以及 EventSource 鉴权问题的 5 种解决方案。一、SSE vs WebSocket不是谁更强而是谁更合适1.1 核心区别一览对比维度SSE (Server-Sent Events)WebSocket通信方向单向服务器 → 客户端全双工双向实时通信协议基础标准 HTTP/HTTPS独立协议 ws/wss需协议升级协议复杂度轻量部署在 HTTP 之上较重需专门服务器库支持浏览器支持除 IE 外主流浏览器均支持主流浏览器均支持数据格式仅 UTF-8 文本文本 二进制自动重连✅ 浏览器原生支持❌ 需应用层手动实现连接数限制同域名通常 6 个无此限制部署复杂度低现有服务器软件都支持高需独立 WebSocket 服务器或网关适用场景单向推送通知、日志、AI 流式回复双向交互聊天、游戏、协同编辑1.2 为什么很多场景选 SSE 不选 WebSocket第一SSE 足够简单。SSE 就是 HTTP 长连接不需要额外的协议握手。你只需要在服务端设置Content-Type: text/event-stream然后往响应流里写数据就行。Node.js、Spring Boot 都有原生支持。第二SSE 自带断线重连。浏览器原生EventSourceAPI 在连接断开后会自动重连开发者一行代码都不用写。WebSocket 断线重连需要自己实现心跳、重试、指数退避……一套写下来几百行代码。第三在 HTTP/2 时代SSE 性能不输 WebSocket。在 HTTP/2 的多路复用能力下SSE 可以和普通 HTTP 请求并行延迟接近 WebSocket。实测数据显示两者在 EPS每秒事件数方面表现相当。第四AI 大模型流式场景SSE 是事实标准。ChatGPT 等大语言模型的流式回复用的就是 SSE。因为这类场景只需要服务器向客户端单向推送生成的文本片段不需要客户端向服务器发消息——杀鸡不需要牛刀。1.3 什么时候必须用 WebSocket一句话原则单向推送选 SSE双向交互选 WebSocket。如果你的场景需要客户端主动向服务端发送数据比如在线聊天双方随时发消息多人在线游戏操作实时同步协同编辑多人同时编辑实时画板那 WebSocket 是唯一选择。但如果只是服务端推送通知、日志流、AI 回复SSE 足够且更优雅。二、EventSource 不能带鉴权头怎么回事2.1 问题现象很多开发者写出这样的代码// ❌ 无效EventSource 不支持 headers 选项constsourcenewEventSource(/api/sse,{headers:{Authorization:Bearer token}});结果要么报错要么 headers 被静默忽略。2.2 根本原因这不是 Bug是设计约束。第一W3C 规范限制。EventSource接口压根就没有提供headers配置项。所有请求头由浏览器自动管理开发者无权干预。第二CORS 安全机制。Authorization属于非简单请求头携带它会触发 CORS 预检preflight。但EventSource的设计不触发 preflight 请求因此浏览器直接禁止携带这类头部。第三架构取舍。SSE 的定位是“服务器单向推送通道”而不是“通用 HTTP 客户端”。为了保持简单、稳定、自动重连的特性刻意剥离了对请求头的控制权。2.3 底层隔离性EventSource使用独立于fetch和XMLHttpRequest的底层网络栈。这意味着无法通过拦截fetch来注入请求头Service Worker 拦截也很困难无法通过 monkey-patch 方式绕过三、5 种解决方案3.1 方案对比总览方案实现方式安全性兼容性后端改动推荐度URL Query 传 Token/sse?tokenxxx⚠️ 中Token 暴露在日志/URL✅ 全平台小⭐⭐Cookie 会话认证Set-CookiewithCredentials✅ 高HttpOnly Secure✅ 全平台中⭐⭐⭐⭐⭐反向代理注入头Nginx/网关层注入 Authorization✅ 高✅ 全平台小网关配置⭐⭐⭐⭐第三方 polyfillextended-eventsource等库✅ 高⚠️ 依赖库无⭐⭐⭐fetch 手动解析用 fetch 发请求手动解析 SSE 流✅ 高✅ 现代浏览器无⭐⭐⭐⭐3.2 方案一URL Query 传 Token快速原型最简单直接的方式consttokenlocalStorage.getItem(auth_token);constsourcenewEventSource(/api/sse?access_token${encodeURIComponent(token)});后端从 Query 参数中提取 Token 并校验。缺点Token 会出现在服务器访问日志、浏览器历史、Referer 头中。仅适合内网环境或短生命周期的一次性 Token。3.3 方案二Cookie 会话认证生产环境推荐利用浏览器自动携带 Cookie的特性这是最优雅的方案。前端// 不需要显式传任何东西浏览器自动带 CookieconstsourcenewEventSource(/api/sse,{withCredentials:true// 跨域时需开启});source.onmessage(event)console.log(event.data);后端登录时设置 Cookie// 登录成功后设置 HttpOnly CookieCookiecookienewCookie(auth_session,sessionId);cookie.setHttpOnly(true);cookie.setSecure(true);cookie.setPath(/api);cookie.setMaxAge(3600);response.addCookie(cookie);服务端校验// 从 Cookie 中读取 sessionId 并校验GetMapping(/api/sse)publicSseEmitterstream(HttpServletRequestrequest){Cookie[]cookiesrequest.getCookies();StringsessionIdextractSessionId(cookies);if(!authService.validate(sessionId)){thrownewUnauthorizedException();}// ... 创建 SSE 流}优点Token 不会暴露在 URL 中设置HttpOnly可防止 XSS 窃取设置Secure和SameSiteStrict增强安全性注意跨域场景下服务端需设置Access-Control-Allow-Credentials: true且Access-Control-Allow-Origin不能为*。3.4 方案三反向代理注入认证头架构级解法在 Nginx 或 API 网关层统一处理认证。Nginx 配置示例location /api/sse { proxy_pass http://backend; # 从 Cookie 中提取 token注入到 Authorization 头 proxy_set_header Authorization Bearer $cookie_auth_token; # SSE 必须关闭缓冲 proxy_buffering off; proxy_cache off; proxy_http_version 1.1; }前端只需访问同域的/api/sseNginx 自动完成 Token 注入。优点前端零改动后端无需感知 Token 来源统一在网关层处理认证3.5 方案四第三方 polyfillextended-eventsource使用支持自定义头的 EventSource 替代实现。// 安装npm install extended-eventsourceimportEventSourcefromextended-eventsource;constsourcenewEventSource(/api/sse,{headers:{Authorization:Bearer token}});原理是用fetch或XMLHttpRequest重新实现了 SSE 协议解析。优点API 与原生 EventSource 几乎一致改动最小。缺点需要额外引入第三方库自动重连等行为可能与原生有细微差异。3.6 方案五fetch 手动解析 SSE 流完全控制放弃原生EventSource用fetch发请求自己解析text/event-stream格式。asyncfunctionconnectSSE(url,token){constresponseawaitfetch(url,{method:GET,headers:{Authorization:Bearer token,Accept:text/event-stream}});constreaderresponse.body.getReader();constdecodernewTextDecoder();letbuffer;while(true){const{done,value}awaitreader.read();if(done)break;bufferdecoder.decode(value,{stream:true});constlinesbuffer.split(\n\n);bufferlines.pop()||;for(consteventoflines){// 解析 SSE 格式data: xxxconstdataevent.replace(/^data:/,).trim();if(data){console.log(JSON.parse(data));}}}}connectSSE(/api/sse,getToken());优点完全控制请求头Authorization、Content-Type 随便加支持 POST 方法不依赖任何第三方库缺点需要手动实现断线重连需要手动解析 SSE 协议格式四、总结一张图看懂怎么选仅服务器→客户端双向通信否是需要服务端推送实时数据通信方向?选 SSE选 WebSocket需要鉴权?直接用 EventSource选择鉴权方案Cookie 认证⭐⭐⭐⭐⭐ 推荐反向代理注入⭐⭐⭐⭐ 架构级fetch 手动解析⭐⭐⭐⭐ 完全控制polyfill 库⭐⭐⭐ 快速集成URL Query 传 Token⭐⭐ 仅限内网核心要点问题答案SSE 为什么不用 WebSocket单向推送场景下SSE 更轻量、更简单、自带重连HTTP/2 下性能不输 WebSocketEventSource 为什么不能带 Authorization 头W3C 规范限制 CORS 安全机制 架构设计取舍生产环境推荐什么方案Cookie HttpOnly最稳妥反向代理注入是架构级解法不想改后端怎么办用fetch 手动解析 SSE 流完全控制请求头一句话总结单向推送用 SSE双向交互用 WebSocket。EventSource 带不了头就用 Cookie 或反向代理绕过去。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑