場景:背景系統需要實時收到電池報警消息,并語音提醒,前台不需要發送任何東西,是以想的是,服務端單向推送
1. 實作EventSource
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}\ndata: ${JSON.stringify(data)}\n\n`)
}
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}\ndata: ${JSON.stringify(data)}\n\n`)
}
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);
}