sse 请求存在跨域吗

99 阅读2分钟

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 的跨域问题,实现安全的跨域数据推送。