场景: 轮询的提代方案,相对于websocket,不能实时,eventsource使用 HTTP 协议。适合不需要双向通信的场景:譬如二维码,扫码后续操作。
优点:相对于轮询,可以减少http请求。
原理: 客户端get请求(不太清楚为啥只能get),服务端返回一个数据流,客户端不会关闭连接。需要空白心跳,保持连接。
兼容性: 可以用event-source-polyfill这个,websocket兼容性会更好。
实现:
客户端:
import {EventSourcePolyfill} from 'event-source-polyfill';
class Eventsource {
constructor() {
this.vm = null;
}
// 初始化
init(vm, url, options) {
const {headers, pathas} = this._initConfig(vm, url, options);
// url拼接路径 baseURL
window.xxx_SSE = new EventSourcePolyfill(`${baseURL + url + pathas.pathas}`, {
withCredentials: false, // 跨域属性
headers: headers
});
window.xxx_SSE.onopen = this._onopen.bind(this);
window.xxx_SSE.onmessage = this._onmessage.bind(this);
window.xxx_SSE.οnerrοr = this._οnerrοr.bind(this);
// 结束后手动移除监听
window.xxx_SSE.removeEmit = function() {
// bus $off
};
}
// 初始化配置
_initConfig(vm, url, options) {
this.vm = vm;
if (window.xxx_SSE) {
window.xxx_SSE.close();
}
return {
headers: {
// 请求头,
Accept: 'text/event-stream;charset-utf-8' // 希望接受的数据类型
},
// get请求拼接参数 使用时params传入数组
pathas: {
pathas: '/' + options.params.join('/')
}
};
}
// 监听链接
_onopen(e) {
// console.log('成功')
}
// 监听消息
_onmessage(event) {
// 触发回调
// bus $emit
}
// 监听错误
_οnerrοr(error) {
// console.log('错误', error)
}
}
export default new Eventsource();
http.install = function(vue, vms) {
vue.prototype.$http = function(url, options, backcall) {
// eventSource
if (options.eventSource) {
vm.$root.Bus.$on('事件', function(res) {
backcall(res);
});
return Eventsource.init(vms, url, options);
}
// axios 逻辑
};
};
注意事项:
1.一般前端都会通过网关(负责验签和加解密)再到具体义务,所以要在网关上做,网关去轮询具体义务。
2.连接中断:
2.1 默认支持断线重连,但是只会一次。
2.2 可以在onerror中处理
2.3 可以定一个定时器30秒,30秒后重启eventsource,在onmessage中重启定时器
3.空白心跳
这个是我在网上随便找的,但是也都差不多。人家就是写个dome,空白心跳就是为了保持链接,真的没必要轮询了就不管成功失败都返回前端,空白心跳30秒左右就可以。
-------------------------------------------------------------------------------------------------------------------------------
段子: 最近房子到期了,找房子。中介说你放心把,房子离地铁很近,我去了一看,确实离地铁近,就是tmd离地铁站太远了。 -- 孟川