介绍
MDN介绍
EventSource
是服务器推送的一个网络事件接口。一个EventSource实例会对HTTP服务开启一个持久化的连接,以text/event-stream
格式发送事件, 会一直保持开启直到被要求关闭。
一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个事件字段,触发的事件与事件字段的值相同。如果没有事件字段存在,则将触发通用事件。
与 WebSockets,不同的是,服务端推送是单向的。数据信息被单向从服务端到客户端分发. 当不需要以消息形式将数据从客户端发送到服务器时,这使它们成为绝佳的选择。例如,对于处理社交媒体状态更新,新闻提要或将数据传递到客户端存储机制(如IndexedDB或Web存储)之类的,EventSource无疑是一个有效方案。
高程介绍
SSE(Server-sent Events,服务器发送事件)
,是围绕只读Comet交互退出的API或者模式。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的MIME类型必须是text/event-steam(Content-type:text/event-steam;)
,而且是浏览器中的JS API能解析格式输出。SSE支持短轮询、长轮询和HTTP流,而且能在断开连接时自动确定何时重新连接。
其他参数、事件、状态看MDN文档,上面的字数够多的了,上代码:
Node起个服务先,下面介绍使用原生SSE和Vue-SSE库都可以用
Node搭个简易版服务
const Koa = require("koa"); //npm安装
const { PassThrough } = require("stream");
const app = new Koa();
let response = {
code: 200,
data: {
id: 1,
name: `Jack`
}
};
app.use(async ctx => {
const { url } = ctx;
if (url === "/sse") {
//!!!必须有
ctx.set({
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive"
});
//!!!必须有
//PassThrough流:一个简单地将输入字节传递到输出的流
let stream = new PassThrough();
ctx.status = 200;
//模拟持续服务端传值给客户端
const interval = setInterval(() => {
let { id } = response.data;
if (id % 2 === 0) {
stream.write("event: customEvents\n");
}
stream.write(`id: ${id}\n`);
stream.write(`data: ${JSON.stringify(response)}\n`);
stream.write("retry: 1000\n");
stream.write("\n\n");
response.data.id++;
}, 2000);
ctx.body = stream;
//流关闭,客户端主动断开连接
stream.on("close", () => {
console.log("连接断开");
clearInterval(interval);
});
}
});
app.listen(8081, () => {
console.log("监听端口:8081,地址:127.0.0.1:8081");
});
原生EventSource
<template>
<div>
<h1>
testSSE:
<button @click="close">关闭</button>
</h1>
<h2>默认事件Message返回值:{{message}}</h2>
<h2>自定义事件customEvents返回值:{{customEvents}}</h2>
</div>
</template>
<script>
export default {
data() {
return {
message: null, //message返回值
customEvents: null, //customEvents返回值
source: null, //SSE实例
};
},
beforeMount() {
this.init();
},
methods: {
close() {
//浏览器关闭SSE连接
this.source.close();
},
init() {
//初始化SSE事件,url为当前同源目录
this.source = new EventSource('/sse');
//监听message事件
this.source.onmessage = (res) => {
let { data } = JSON.parse(res.data);
this.message = data;
};
//监听自定义customEvents事件
this.source.addEventListener('customEvents', (res) => {
let { data } = JSON.parse(res.data);
this.customEvents = data;
});
},
},
};
</script>
Vue-SSE包
vue-sse Vue版本
event-source-polyfill 兼容浏览器版本
# npm
npm install --save vue-sse@2.5.0
# OR yarn
yarn add vue-sse@2.5.0
#OR pnpm
pnpm add vue-sse@2.5.0
import VueSSE from 'vue-sse';
// using defaults
Vue.use(VueSSE);
// OR specify custom defaults (described below)
Vue.use(VueSSE, {
format: 'json', //数据格式
url: '/my-events-server', //路径
withCredentials: true, //标识为open? // withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
forcePolyfill:false, //强制使用原生SSE,使用另一个库event-source-polyfill
polyfill: true, //支持旧版浏览器
polyfillOptions:null, //配置参数
});
<template>
<div>
<h1>
testVueSSE:
<button @click="close">关闭</button>
</h1>
<h2>默认事件Message返回值:{{message}}</h2>
<h2>自定义事件customEvents返回值:{{customEvents}}</h2>
</div>
</template>
<script>
export default {
data() {
return {
message: null, //message返回值
customEvents: null, //customEvents返回值
vueSse: null, //实例
};
},
mounted() {
//实例化
this.vueSse = this.$sse.create({
url: '/sse',
format: 'json',
withCredentials: true
});
this.init();
},
sse: {
//配置后自动添加断开连接事件,源码里面是做了判断,
//然后加在组件 beforeDestroy 生命周期里
cleanup: true,
},
methods: {
close() {
//浏览器关闭SSE连接
this.vueSse.disconnect();
},
init() {
let vueSse = this.vueSse;
//监听 message
vueSse.on('message', this.handleMessage);
//监听 customEvents
vueSse.once('customEvents', this.handleCustomEvents);
//里面的 on、once、off 是用了发布订阅模式,
//源码 once 方法这有点小问题,写文章时改了
//源码但还没提PR(主要是没提过,不会弄)
//执行 connect() 返回个Promise,
vueSse
.connect()
.then((sse) => {
console.log("We're connected!");
setTimeout(() => {
//解绑 message
vueSse.off('message', this.handleMessage);
console.log('Stopped listening to event-less messages!');
}, 6000);
})
.catch((err) => console.error('Failed make initial connection:', err));
},
//message回调
handleMessage(res) {
console.info('Message:', res);
let { data } = res;
this.message = data;
},
//handleCustomEvents回调
handleCustomEvents(res) {
let { data } = res;
console.info('customEvents:', data);
this.customEvents = data;
},
},
};
</script>
ps:第一次写,很多地方没有涉及,有不对的地方麻烦指出,谢谢
参考文章
搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE