EventSource VS WebSocket
EventSource
定义
EventSource 也称为 SSE(Server-Sent Events),是服务器推送的一个网络事件接口,一个 EventSource 会对 http 服务开启一个持久化链接,它发送的事件格式是‘text/stream’,开启 EventSource 事件后,它会一直保持开启状态,直到被要求关闭
Server 使用
我采用的是 node + Koa 的方式,由于它是属于 http 的请求方式,所以通过路由匹配,主要需要设置{‘Content-Type’: ’text/event-stream’}形式
const app = new Koa();
app.use(async (ctx, next) => {
if (ctx.path === '/stream') {
ctx.request.socket.setTimeout(0)
ctx.req.socket.setNoDelay(true)
ctx.req.socket.setKeepAlive(true)
ctx.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
})
const stream = new PassThrough()
ctx.status = 200
ctx.body = stream
setInterval(() => {
stream.write(`data: ${new Date()}\n\n`)
}, 1000)
return
}
try {
await next()
}
})
client 使用
初始化事件对象, EventSource 第一个参数是访问的 http 的 url, 第二个 config 主要配置跨域属性, 3000 是客户端端口,通过 proxy 代理到后端
let serverEvent = new EventSource("http://localhost:3000/stream", {
withCredentials: true,
});
相关的事件监听方法
serverEvent.onopen = (event) => {
console.log(event, "onopen----event00000");
};
// 连接成功,消息推送
serverEvent.onmessage = (event) => {
console.log(event, "onmessage----event00000");
};
// 服务发生异常,譬如跨域问题等
serverEvent.onerror = (event) => {
console.log(event, "onerror----event00000");
};
由于它在 http 下,所以你在 network 中可以找到对应的 api,在里面有 EventStream 就是对应的返回结果,如果报错可以通过查看返回的 status 等信息排查问题原因
WebSocket
定义
WebSocket 可以在用户的浏览器和服务器之间打开交互的通信方式,使用此 API,您可以向服务器发送消息并接受事件驱动的响应,而无需通过轮训服务器的方式获得相应。
server 使用
在 server 端,新建目录文件 wss/websocket.js, 其内容如下, 其中 WebSocket.Server 的第一个参数是后端开启的 server 服务,path 对应的是 websocket 的路径,不填写默认是’/’,我这里采用的 ws 的库,另外还有像 socket.io 等库
const WebSocket = require("ws");
class ws {
static ws = WebSocket.Server; // 默认实例
static init(server) {
// 创建实例
// eslint-disable-next-line new-cap
console.log("this.init, this.init, this.init, ");
this.ws = new WebSocket.Server({ server, path: "/websocket" });
this.ws.on("connection", async (ws, request) => {
let count = 0;
this.ws.clients.forEach((client) => {
setInterval(() => {
const data = {
id: count,
firstName: `first-${count}`,
};
client.send(JSON.stringify(data));
count++;
}, 2000);
});
this.ws.send("connected");
});
}
}
module.exports = ws;
client 使用
这里 WebSocket 后面添加的是 ws 对应的 url,其中 3000 是客户端端口,websocket 对应的路径同 server 端 WebSocket.Server 第二个参数 path 对应。
const exampleSocket = new WebSocket("ws://localhost:3000/websocket");
exampleSocket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data?.id >= 3) {
exampleSocket.close();
}
};
需要注意的是,这里如果需要访问 proxy 到服务端,通过 vite/webpack 相关配置里需要加{ws: true}的属性,如下图所示
另外,它的数据查看方式是在 network 下的 ws 中查看
对比
EventSource | WebSocket |
---|---|
单向传输(server 到 client) | 双向传输 |
基于 http 协议 | 基于 tcp 协议 |
只支持文本(utf-8) | 支持二进制/文本(utf-8)格式数据传输 |
浏览器限制传输个数(chrome 限制 6 个,因为是 http 请求,http1.0 有限制) | 浏览器不限制 |
轻量级协议,实现简单 | 重量级协议,实现复杂 |
支持断开重连 | 需要额外部署 |
不支持跨域,需要设置 header | 支持跨域 |
没有防火墙阻塞 | 有防火墙 |