WebSocket 前端 Vue 长连接 断线重连
文章目录WebSocket简介额外注意点实际开发代码创建WebSocket工具文件创建WebSocket连接初始化WebSocket心跳防止断开连接收到信息后区分业务信息和心跳信息定义关闭连接的方法,方便登出时使用将关闭和创建连接的方法在main中注册全局,方便业务代码中使用chrome调试webpack和nginx中的代理设置webpack配置websocket代理nginx配置websocke
文章目录
需求:服务端出现数据改动之后,web端提示用户某某数据改动(本文主要涉及web端的处理)
想法:
- 通过web端轮询http请求,这种逻辑简单易懂,前后端的开发也比较简单,但是一直循环发送http请求不适合用户较多,注重性能的web应用。(http请求会带上大量头部信息,实际上有效数据可能较少,浪费带宽)
- 通过html5的websocket协议,而不是通过http请求来实现,这种情况下连接一旦建立,就可以双方互相发送数据,从性能方面来讲比轮询要优越,当然开发上会相对复杂一点。这里采用websocket的方法来实现。
WebSocket简介
WebSocket是基于TCP连接的协议,方便客户端和服务端建立端对端通信。
客户端向服务器发送WebSocket连接请求,连接建立之后,双方就可以通过TCP来建立连接交换数据
后台提供的WebSocket连接地址一般是ws://www.test.com/project/interface
前面是ws开头而不是http开头,后台接口也是要单独开发的。
如果有wss开头的,其中 wss 表示在 TLS 之上的 Websocket
参考:https://www.runoob.com/html/html5-websocket.html
常用主要注意WebSocket的4个事件和2个方法
WebSocket 协议本质上是一个基于 TCP 的协议。
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了
兼容性暂时没有测试过,因为目前产品都会要客户使用chrome-,-
websocket和socket是不同的东西,具体区别这里不做展开了
额外注意点
如果浏览器刷新页面,websocket的连接是会断开的!
服务器的nginx一般会进行配置,websocket如果一小段时间不和服务器通信是会被断开的!
实际开发代码
这里项目是Vue+Element的前端项目
使用WebSocket不用引入其他包
创建WebSocket工具文件
先建立utilWebSocket.js工具文件,用来存放WebSocket相关的代码,然后将websocket在main.js中注册到全局方便调用
这里先定义一个websocket变量,代表websocket连接
//websocket对象
let webSocket = null;
创建WebSocket连接
websocket连接只需要通过 webSocket = new WebSocket(wsUri);
来创建就可以了,wsUri是后端提供的ws接口地址
这里通过try catch包裹创建websocket的代码,来保证如果第一时间没有建立连接,之后也会继续去申请建立连接
//创建webSocket连接
let createWebSocket = () => {
try {
let path = window.location.href;
const wsUri = path.substring(0, path.indexOf("#")).replace('http', 'ws') + `customer/websocket/${sessionStorage.getItem('addUserId')}`;
//其实只需要定义一个变量存放后端提供的WebSocket接口地址,然后
webSocket = new WebSocket(wsUri);
//初始化websocket连接
initWebsocket();
} catch (e) {
console.log('尝试创建连接失败');
//如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
reConnect();
}
};
reConnect是一个重连方法,这样如果第一时间没有建立连接或者之后由于各种原因连接断开了,就可以调用reConnect方法
//连接标识 避免重复连接
let isConnect = false;
//断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let rec;
//定义重连函数
let reConnect = () => {
console.log('尝试重新连接');
//如果已经连上就不在重连了
if(isConnect) return;
rec&&clearTimeout(rec);
// 延迟5秒重连 避免过多次过频繁请求重连
rec=setTimeout(function(){
createWebSocket();
},5000);
};
初始化WebSocket
//初始化webSocket连接
let initWebsocket = () => {
//WebSocket连接建立之后会调用onopen方法
webSocket.onopen = function (e) {
console.log('open');
//连接建立后修改标识
isConnect=true;
// 建立连接后开始心跳
// 因为nginx一般会设置例如60s没有传输数据就断开连接 所以要定时发送数据
heartCheck.start();
};
//当websocket收到服务器发送的信息之后 会调用onmessage方法 getMsg用来封装获取到服务器的消息进行处理,下面会说明
webSocket.onmessage = function (e) {
getMsg(e);
//获取消息后 重置心跳
heartCheck.reset();
};
//当websocket因为各种原因(正常或者异常)关闭之后,会调用onclose方法
webSocket.onclose = function (e) {
console.log('close');
//连接断开后修改标识
isConnect=false;
};
//当websocket因为异常原因(比如服务器部署、断网等)关闭之后,会调用onerror方法
//在onerror中需要调用reConnect方法重连服务器
webSocket.onerror = function (e) {
console.log('error');
//连接断开后修改标识
isConnect=false;
//连接错误 需要重连
reConnect();
};
};
这里用到了heartCheck
的两个方法,
heartCheck是为了应对nginx关闭不传数据的连接,
每一段时间传一个特殊数据,类似发送心跳包
心跳防止断开连接
heartCheck心跳工具的代码如下
//心跳发送/返回的信息
//服务器和客户端收到的信息内容如果如下 就识别为心跳信息 不要做业务处理
let checkMsg='heartbeat';
//心跳设置
var heartCheck = {
//每段时间发送一次心跳包 这里设置为20s
timeout: 20000,
//延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)
timeoutObj: null,
//一段时间后发送心跳包
start: function () {
this.timeoutObj = setTimeout(function () {
if(isConnect) webSocket.send(checkMsg);
}, this.timeout);
},
// 接收到服务器的信息之后要重置心跳发送的方法
reset: function () {
clearTimeout(this.timeoutObj);
this.start();
},
};
核心思想就是只要客户端收到消息了,就结束这一轮的心跳,开始下一轮的心跳!
收到信息后区分业务信息和心跳信息
//获得消息之后 区别是心跳还是业务信息 如果是业务信息特殊处理(这里就用Element的notify才处理提醒)
let getMsg = (e) => {
console.log('message');
console.log(e.data);
if ((e.data != '连接成功') && (e.data != checkMsg)) {
this.$notify.error({
title: '失败',
message: e.data,
duration: 0,
});
}
};
定义关闭连接的方法,方便登出时使用
这里将启动和关闭连接的方法暴露出去,登入和登出时来调用这两个方法
//关闭连接
let closeWebSocket = () => {
webSocket.close();
};
export default {
createWebSocket: createWebSocket,
closeWebSocket: closeWebSocket,
}
将关闭和创建连接的方法在main中注册全局,方便业务代码中使用
import utilWebsocket from './util/utilWebSocket'
Vue.prototype.closeWebSocket = utilWebsocket .closeWebSocket;
Vue.prototype.createWebSocket = utilWebsocket .createWebSocket;
这样直接在登录之后调用this.createWebSocket()
方法就可以了
登出调用this.closeWebSocket()
方法就可以了
chrome调试
在network中开启WS过滤,就可以看到当前项目的websocket连接情况了
注意Header中的Connection属性是Upgrade
Upgrade属性是websocket
[外链图片转存失败(img-hom2JhzK-1562862891215)(./1562857587799.png)]
webpack和nginx中的代理设置
websocket的代理设置和http是不一样的
webpack配置websocket代理
普通的http请求的代理
'/admin/': {
target: 'http://192.168.166.107:8081',
changeOrigin: true,
},
websocket的代理如下
'/customer/websocket/': {
target: 'ws://192.168.166.107:8083',
ws:true,
secure:false,
},
nginx配置websocket代理
服务器配置这个代理就比webpack要复杂一些,较高版本的nginx一般都支持webpack代理
自己用的版本是否支持自行查询。。
以下是简单的配置 还有其他详细配置这里就不展开了
location /customer/websocket {
proxy_pass http://192.168.166.112:8083/customer/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
nginx的配置一定要注意!不然会被误认为是http的get请求 一直返回200状态码
更多推荐
所有评论(0)