场景:后台系统需要实时收到电池报警消息,并语音提醒,前台不需要发送任何东西,所以想的是,服务端单向推送
1. 实现EventSource参考博客:
https://www.jqhtml.com/41272.html
https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events
2. 利用events监听触发事件,主动推送消息
前端代码
<script type="text/javascript"> if(typeof(EventSource)!=="undefined"){ let source=new EventSource("http://192.168.254.244:3001/api/messageNotic"); source.addEventListener('test',function(e){ console.log(e) }); source.onmessage=function(event) { console.log(event) document.getElementById("result").innerHTML+=event.data + "<br>"; }; }else{ document.getElementById("result").innerHTML="抱歉,你的浏览器不支持 server-sent 事件..."; } </script>
后端代码
// 可读流 const Readable = require('stream').Readable; function RR() { Readable.call(this, arguments); } RR.prototype = new Readable(); RR.prototype._read = function (data) { } const sse = (stream, event, data) => { return stream.push(`event:${event} data: ${JSON.stringify(data)} `) } exports.messageNotic = async (ctx, next) => { let stream = new RR() ctx.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' }); // sse(stream, 'test', { remindFlag: new Date() }); ctx.body = stream; // 每过30秒,发送一条注释语,保持和web端的连接。 interval = setInterval(function () { sse(stream, 'test', { remindFlag: new Date() }); }, 1000 * 30); // 监听当web端关闭eventSource, 清除定时器 ctx.req.connection.addListener("close", function () { clearInterval(interval); }, false); }
到了这步,其实可以完成推送了,
但是如果想在产生报警日志的时候,发送提醒消息,就需要继续操作,
借用events依赖,当监听到某个事件的触发,就主动推送一条消息,
改造之后的代码如下:
// events事件
const events = require('events');
const eventEmitter = new events.EventEmitter();
// 增加一个监听事件 // 当监听到abnormalHandler 异常函数触发,往前端推送带有报警得消息 async function abnormalHandler() { eventEmitter.emit("abnormalHandler"); } function RR() { Readable.call(this, arguments); } RR.prototype = new Readable(); RR.prototype._read = function (data) { } const sse = (stream, event, data) => { return stream.push(`event:${event} data: ${JSON.stringify(data)} `) } exports.messageNotic = async (ctx, next) => {
当监听到abnormalHandler事件触发,就主动推送一条消息 eventEmitter.on("abnormalHandler", function () { console.log("data_receive ---> connection"); sse(stream, 'test', { remindFlag: 1 }); }); var stream = new RR() ctx.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' }); // sse(stream, 'test', { remindFlag: new Date() }); ctx.body = stream; // 每过30秒,发送一条注释语,保持和web端的连接。 interval = setInterval(function () { sse(stream, 'test', { remindFlag: new Date() }); }, 1000 * 30); // 监听当web端关闭eventSource, 清除定时器 ctx.req.connection.addListener("close", function () { clearInterval(interval); }, false); }