SSE 消息推送 异常解决方案

部分问题解决方案

1、SSE 报错会不会持续建立连接?
连接后报错可以重新连接,重新连接间隔由服务端传输字段设定
2、主动写销毁方法与页面直接关闭是否有性能区别?
* 关闭 MES 菜单标签页不会自动关闭 SSE 连接 (可在页面销毁前调用方法关闭 SSE 连接)
* 关闭浏览器标签页会关闭
* 如果关闭 MES 菜单标签页不会自动关闭怎么处理?
在页面代码中写上,在页面销毁前关闭通道 和关闭浏览器标签页没有性能区别

 methods:{   
 getSSE() {  
 let that = this;  
 this.source = new EventSource("http://10.1.1.133:8081/sseMsg/pushWeb/admin");  
 this.source.addEventListener("message", (e) => {  
 console.log(e);  
 });  
 },  
 },  
 ...   
 beforeDestroy() {  
 this.source.close()   
 // 调用SSE关闭方法  
 }  ...

3、浏览器会有最大连接限制 6 个连接
pSlUh4K.png
参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events
4、SSE 管道向后台请求时,是否可以控制频次(为避免对服务器造成压力),频次可能是服务端控制的,待确认?


重连时间可由 retry 字段返回 默认是 3s
可尝试使用 SseEmitter https://www.cnblogs.com/jun1019/p/10886079.html
达摩院 SSE http://119.96.220.140:9099/article/1629195920546
5、后台使用了 return ’data’代码语句,是否会导致每次都在请求后台,重新建立连接


1、return data 方式不合理,应使用类似这种解决方式
pSlU59O.png
2、如果使用 return 数据传输前台后 return 导致通道关闭触发 SSE 断线重连 会继续服务端发送请求建立连接
* return data
pSlUoge.png
pSlUbDA.png
参考解决办法 : https://www.jianshu.com/p/100b82730e15 修改后,连接成功后只会存在一个持续的 SSE 连接
* 修改后的
pSlaSgg.md.png pSlapvQ.md.png
6、异常重连机制


两种情况会导致浏览器重新发起连接:一种是时间间隔到期,二是由于网络错误等原因,导致连接出错,三是请求建立通道失败也会重连
重连会触发事件: open 建立连接时触发;error 与连接无法建立时触发)
服务端可以用 retry 字段,设置浏览器重新发起连接的时间间隔。默认为 3s (需要通道正常连接后,才能获取服务端设置的 retry 属性)
retry: 10000\ndata: ${数据} \n\n
重连次数限制
* 可在前台设置监听 error 次数

    const source = new EventSource("/sseMsg/pushWeb/admin");   
    source.onopen = (e) => {  console.log("open", e); };   
    source.onmessage = (e) => {  console.log("message", e);  // 处理业务数据   
     };   
    ...   
    // 在报错监听上 添加次数限制   
    source.onerror = (e) => {    
     let times = 5    // 设置重连次数 可结合retry使用  
     times--  
     if (times == 0) {  
     source.close()   // 关闭SSE通道  
     times = 5  
     }   
    };

SSE 介绍与使用

使用说明参照:达摩院论坛:服务器推送客户端方案 SSE 在规则引擎中的应用
* SSE 接收数据的固定格式 retry:${毫秒数}\ndata:${返回数据}\n\n
* retry: 指每隔多久重连一次服务器, 谷歌默认是 3000 毫秒
* data: 是指要接收的数据
* SSE 触发重连情况:
* 时间间隔到期;
* 网络错误等原因,导致连接出错;
* 请求建立通道失败也会重连;
* 如后台异常或网络故障,两种方案
* 前台限制重连次数
* 优点:可及时停止 SSE 重连机制
* 缺点:设置重连次数需要手动建立连接
* 服务端断开期间,一直会重复建立连接,当达到限制次数时会关闭 SSE 通道,当服务端连接上后,需要手动去建立 SSE 连接;(通常方法:刷新页面重新建立连接)
* 不限制重连次数
* 优点:服务器断开期间,会尝试重连,当服务恢复后,会自动连接上服务器
* 缺点:服务器断开期间,会重复建立连接,如有异常日志记录情况会造成日志量过大

// 在报错监听上 添加次数限制   
source.onerror = (e) => {  
 let times = 5  
 // 设置重连次数 可结合retry使用  
 times--  
 if (times == 0) {  
 source.close()   
 // 关闭SSE通道  
 times = 5  
 }   
};

大屏看板数据推送方案

<script>   
 export default {   
 methods:{  
 getSSE() {   
 // 建立SSE连接通道   
 let that = this  
 this.source = new EventSource("SSE连接");   
 // 有数据传来时触发  
 this.source.addEventListener("message", (e) => {   
 console.log(e);   
 });   
 // 出现网络错误,或服务端连接失败时触发   
 this.source.addEventListener("error", (e) => {  
 // 限制重连次数方法  
 // let times = 5  
 // 设置重连次数 可结合retry使用   
 // times--   
 // if (times == 0) {  
 //  that.source.close()   
 // 关闭SSE通道   
 //   times = 5  
 // }   
 });   
 },   
 },   
 mounted(){   
 this.getSSE()  
 },   
 beforeDestroy() {   
 this.source.close()   // 调用SSE关闭方法   
 }   
 }   
</script>

app 数据推送方案
使用说明参照: 达摩院论坛:App SSE 消息推送
SSE 连接跨域

样例: nginx 配置

 upstream sse {  
 ip_hash;  
 #keepalive 300;  
 #sticky;  
 server 192.168.40.214:8081;    // SSE服务地址  
 }  
 location /sseServeUrl {  
 proxy_pass http://sse;  
 tcp_nodelay on;  
 proxy_set_header Host $host;  
 proxy_set_header X-Real-IP $remote_addr;  
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
 # Handle request  
 }

前端使用:

// index.html  
...  
 window.SITE_CONFIG["sseServerUrl"] = "/sseServeUrl";  
...

SSE 使用

...  
 source = new EventSource(window.SITE_CONFIG["sseServerUrl"] + "/*****/****"); // 配置接口  
...

如果遇到首次请求事件间距过长 或长时间请求不到超时 需添加
参考链接 :https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx

location /sseServeUrl {  
 proxy_pass http://sse;   
 tcp_nodelay on;  
 proxy_set_header Host $host;  
 proxy_set_header X-Real-IP $remote_addr;  
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
​  # Handle request 
 # 下面代码处理超时或长时间请求不到  
 proxy_set_header Connection '';  
 proxy_http_version 1.1;  
 chunked_transfer_encoding off;  
 proxy_buffering off;  
 proxy_cache off;  
 }