前言
随着互联网的发展,前后端分离的模式越来越流行,为了实现高效的数据传输,前端开发者通常需要使用 Server-sent 事件。Server-sent 事件 (SSE) 是一种可向客户端推送实时数据的浏览器 API,它的本质是持久化的 HTTP 连接,它允许服务器不断地向客户端推送数据流。
然而,使用 Server-sent 事件时经常会遇到跨域访问 (CORS) 错误。在本文中,我们将深入了解 Server-sent 事件和 CORS 错误,并提供解决方案及示例代码。
Server-sent 事件
Server-sent 事件 (SSE) 是一种使用 HTTP 服务器向浏览器推送数据的方法。该通信协议基于持久的 HTTP 连接,允许服务器推送数据流,而客户端则使用 EventSource API 来接收这些数据。在传输过程中,服务器可以轻松处理未决请求,从而解决了客户端与服务器间的并发性问题。
SSE API
以下是 SSE API 的基本语法:
const source = new EventSource(url, eventSourceInitDict);
参数说明:
- url:SSE 服务器 URL。
- eventSourceInitDict:可选参数,用于自定义 SSE 连接选项,例如自定义头部。
SSE 客户端 API 仅包含一个 EventSource 对象。使用它,我们可以通过指定 SSE 服务器的 URL 地址来建立数据通道:
const source = new EventSource('https://example.com/api/sse');
然后,可以使用 onmessage 对象来接收数据:
source.onmessage = function(event) { console.log(event.data); };
SSE 格式
SSE 格式基于纯文本,使用了一个简单的格式:每个 SSE 事件由包含以下数据的标题与消息组成:
event: <event-name> data: <event-data> id: <event-id> retry: <retry-time>
- event-name:事件类型,通常用于进一步处理事件内容。
- event-data:事件数据,与事件类型相关联。
- event-id:事件 ID,允许服务器定义全局唯一事件 ID,客户端会将上一个事件 ID 保存下来,并使用 Last-Event-ID 头部重新连接时发送给服务器。
- retry-time:在 SSE 连接中断后,可以通过使用此属性来指定重新连接的所需时间。
SSE 服务器
SSE 服务器是一种 HTTP 服务器,在服务器推送新数据时,客户端将自动接收到推送。因此,为了实现 SSE,需要部署一个 HTTP 服务器和 SSE 事件处理器。以下是 SSE 服务器的 Node.js 实现示例:
const http = require('http'); http.createServer(function(request, response) { response.writeHead(200, { 'Content-Type': 'text/event-stream', // 告诉浏览器:这是一个 SSE 服务 'Cache-Control': 'no-cache', 'Access-Control-Allow-Origin': '*', // 开放 CORS 'Connection': 'keep-alive' }); // 每隔 5 秒向客户端发送服务器当前时间 setInterval(function() { let time = new Date().toLocaleString(); response.write('data: ' + time + '\n\n'); }, 5000); }).listen(8000);
客户端 JavaScript 代码:
const source = new EventSource('http://localhost:8000'); source.onmessage = function(event) { console.log(event.data); };
CORS 错误
CORS (Cross-Origin Resource Sharing, 跨源资源共享) 是浏览器实施的一种保护机制,用于限制某个域的 JavaScript 与来自其他域的资源(比如音频、视频、web 字体等)之间的通信。这种机制可以防止恶意脚本对用户数据等的攻击。
但是,Server-sent 事件使用持久的 HTTP 连接,这种连接通常需要使用预检(OPTIONS)请求,这种请求会触发 CORS 机制,从而出现 CORS 错误,导致 SSE 连接中断。以下是如何解决 SSE 的 CORS 错误:
解决方案
通常,解决 CORS 错误的解决方案有以下几种方式:
方法 1:增加 Access-Control-Allow-Origin 头部
由于跨域问题,服务器通常需要设置响应头部 Access-Control-Allow-Origin,以允许来自任何域名的请求。例如:
Access-Control-Allow-Origin: *
然而,Server-sent 事件相比其他类型的请求,它不会立即断开连接,这样会导致在建立了连接之后才会发送 CORS 错误。对于这种情况,需要在响应头部添加以下两行:
Access-Control-Allow-Origin: * Connection: keep-alive
以下是 Node.js 实现 SSE 服务器的示例:
const http = require('http'); http.createServer(function(request, response) { response.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Access-Control-Allow-Origin': '*', 'Connection': 'keep-alive' }); setInterval(function() { let time = new Date().toLocaleString(); response.write('data: ' + time + '\n\n'); }, 5000); }).listen(8000);
方法 2:使用代理服务器
另一种解决方案是使用代理服务器将请求从浏览器转发到 SSE 服务器。这种方法可以控制请求的响应头部,从而解决 CORS 问题。以下是一个使用 Nginx 的代理服务器:
# Nginx 配置文件 http { server { location /api/sse { proxy_pass http://localhost:8000; proxy_set_header Access-Control-Allow-Origin "*"; proxy_set_header Connection "keep-alive"; } } }
方法 3:使用 JSONP
JSONP(JSON with Padding,用于跨域通信)是一种利用 script 标签实现跨域请求的技术。JSONP 请求不是异步请求,而是通过设置回调函数的方式,将响应内容封装在函数执行中返回。
以下是 SSE 服务器使用 JSONP 解决 CORS 问题的 Node.js 实现示例:
const http = require('http'); http.createServer(function(request, response) { let callback = request.query.callback; response.write(callback + '('); setInterval(function() { let time = new Date().toLocaleString(); response.write(JSON.stringify({time: time}) + ','); }, 5000); }).listen(8000);
客户端 JavaScript 代码:
let script = document.createElement('script'); script.src = 'http://localhost:8000/?callback=doSomething'; function doSomething(data) { console.log(data.time); } document.body.appendChild(script);
总结
Server-sent 事件 (SSE) 是一种使用 HTTP 服务器向浏览器推送数据的方法,它可以帮助前端开发者实现高效的数据传输。然而,在使用 SSE 时,经常会遇到 CORS (跨源资源共享) 错误,在本文中,我们介绍了 SSE 的相关知识,并提供了三种解决 SSE 的 CORS 错误的方法。通过本文的学习,您可以深入了解 SSE,掌握 SSE 在实际项目中的应用。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a2271eadd4f0e0ffa33f84