SSE(Server-Sent Events)会受到浏览器的跨域限制。其行为与常规的 AJAX 请求类似,需遵循 CORS(跨域资源共享) 规则。以下是具体分析及解决方案:
1. 跨域问题的表现
- 默认禁止跨域:若客户端(如
https://client.com
)通过EventSource
连接不同源的服务器(如https://api.server.com
),浏览器会直接阻断请求,控制台报错:
Access to XMLHttpRequest at 'https://api.server.com/stream' from origin 'https://client.com'
has been blocked by CORS policy.
2. 解决方案:CORS 配置
需在 服务器端 设置以下响应头,允许跨域访问:
基础配置
Access-Control-Allow-Origin: https://client.com # 允许指定源
# 或
Access-Control-Allow-Origin: * # 允许所有源(不推荐生产环境使用)
进阶配置(如需携带凭证)
若请求需要携带 Cookie 或认证头(如 Authorization
),需额外配置:
Access-Control-Allow-Credentials: true
同时,客户端需在初始化 EventSource
时设置 withCredentials
:
const es = new EventSource('https://api.server.com/stream', {
withCredentials: true
});
3. 预检请求(Preflight)的特殊性
- SSE 通常无需预检:因为
EventSource
默认使用GET
方法且无自定义请求头,浏览器不会触发OPTIONS
预检请求。 - 例外场景:若添加了自定义头(如
X-Custom-Header
),需服务器处理OPTIONS
请求并返回:
Access-Control-Allow-Headers: X-Custom-Header
4. 常见错误排查
- 通配符
*
与凭证冲突:
若设置Access-Control-Allow-Origin: *
且同时启用withCredentials
,浏览器会拒绝连接。需明确指定允许的源(如https://client.com
)。 - 协议/端口/域名不匹配:
即使主域名相同,子域(如a.client.com
→b.client.com
)、端口(如80
→8080
)或协议(http
→https
)不同也会触发跨域拦截。
5. 示例:Node.js 服务端配置
const http = require('http');
http.createServer((req, res) => {
// 设置 CORS 头
res.setHeader('Access-Control-Allow-Origin', 'https://client.com');
res.setHeader('Access-Control-Allow-Credentials', 'true');
// SSE 特有头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 推送数据(示例)
setInterval(() => {
res.write(`data: ${new Date().toISOString()}\n\n`);
}, 1000);
}).listen(3000);
6. 浏览器兼容性
- 所有现代浏览器均支持 SSE 的 CORS 规则(包括 Chrome、Firefox、Safari、Edge)。
- 注意:IE/旧版 Edge 不支持
EventSource
,需 polyfill(如event-source-polyfill
)。
通过合理配置 CORS 头,即可解决 SSE 的跨域问题,实现安全的跨域数据推送。