详解微信小程序实现WebSocket心跳重连


Posted in Javascript onJuly 31, 2018

最近在开发小程序用到了WebSocket,小程序提供了相应的原生API,与H5的API使用方式上有一些区别,所以流行的H5的一些成熟的类库使用起来有些困难,而原生API又存在一些缺陷,所以就自己实现了一套心跳重连机制。

惯例,先简单介绍一下Websocket。

Websocket简介

Websocket是什么

WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

为什么需要Websocket

HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。

所以当我们想服务器主动给客户端发送消息,HTTP是做不到的,我们只能使用轮询或者长轮询来实现类似的功能,这样的方式效率低并且浪费资源,为了解决这样的问题,WebSocket诞生了。

小程序中的WebSocket

小程序WebSocket的API

把你给懒得!自己官网看去!

为什么要做心跳重连

在使用原生WebSocket的时候,我们经常会感觉不太稳定,服务端发送的消息有时候客户端接收不到,或者是客户端发送的消息服务端接收不到,虽然WebSocket也提供了onError和onClose的方法,但是经常会有各种未知情况导致断开连接而并不触发Error或Close事件。这样就导致实际连接已经断开了,而客户端和服务端却不知道,还在傻傻的等着消息来。

所以我们要解决的问题就很清晰了:

保证连接状态,连接断开时让客户端与服务端都能知道,进而重连。

上代码

页面载入后,我们连接socket先

onLoad(){
  this.linkSocket()
 },
 linkSocket(){
  let that = this
  wx.connectSocket({
   url: app.globalData.wsUrl + 'websocket?' + this.data.taskId + '&' + this.data.userId,
   success() {
    console.log('连接成功')
    that.initEventHandle()
   }
  })
 },

绑定事件

然后调用initEventHandle来绑定各种各样的事件

initEventHandle(){
  let that = this
  wx.onSocketMessage((res) => {
   //收到消息
  })
  wx.onSocketOpen(()=>{
   console.log('WebSocket连接打开')
  })
  wx.onSocketError(function (res) {
   console.log('WebSocket连接打开失败')
  })
  wx.onSocketClose(function (res) {
   console.log('WebSocket 已关闭!')
  })
 },

这个先放在这我们一会往里填东西

断线重连

reconnect(){
  if (this.lockReconnect) return;
  this.lockReconnect = true;
  clearTimeout(this.timer)
  if (this.data.limit<12){
   this.timer = setTimeout(() => {
    this.linkSocket();
    this.lockReconnect = false;
   }, 5000);
   this.setData({
    limit: this.data.limit+1
   })
  }
 },

我们设置一个锁和最大的重连次数,避免出现无限重连的情况,为了不给服务器太大的压力我这里设置的是5秒重试一次,最多请求12次。

改造一下initEventHandle这样我们就可以实现一般的触发Error的断线重连。

initEventHandle(){
  let that = this
  wx.onSocketMessage((res) => {
   //收到消息
  })
  wx.onSocketOpen(()=>{
   console.log('WebSocket连接打开')
  })
  wx.onSocketError((res)=>{ 
   console.log('WebSocket连接打开失败')
   this.reconnect()
  })
  wx.onSocketClose((res)=> {
   console.log('WebSocket 已关闭!')
   this.reconnect()
  })
 },

关键的来的---心跳对象

先撸为敬

let heartCheck = {
 timeout: 10000, 
 timeoutObj: null,
 serverTimeoutObj: null,
 reset: function () {
  clearTimeout(this.timeoutObj);
  clearTimeout(this.serverTimeoutObj);
  return this;
 },
 start: function () {
  this.timeoutObj = setTimeout(()=> {
   console.log("发送ping");
   wx.sendSocketMessage({
    data:"ping",
    // success(){
    //  console.log("发送ping成功");
    // }
   });
   this.serverTimeoutObj = setTimeout(() =>{
    wx.closeSocket(); 
   }, this.timeout);
  }, this.timeout);
 }
};

心跳对象内timeout为每10秒发一次心跳,timeoutObj、serverTimeoutObj是清除定时器用的对象,reset方法重置定时器,start发送心跳。

继续改造我们的initEventHandle

initEventHandle(){
  let that = this
  wx.onSocketMessage((res) => {
   //收到消息
   if (res.data == "pong"){
    heartCheck.reset().start()
   }else{
    \\处理数据
   }
  })
  wx.onSocketOpen(()=>{
   console.log('WebSocket连接打开')
   heartCheck.reset().start()
  })
  wx.onSocketError((res)=>{ 
   console.log('WebSocket连接打开失败')
   this.reconnect()
  })
  wx.onSocketClose((res)=> {
   console.log('WebSocket 已关闭!')
   this.reconnect()
  })
 },

打开连接的时候调用start开始心跳,每隔10秒向服务端发送消息"ping",服务端接收到消息后给我们回个话"pong",就好像微信聊天。

在吗?

在吗?

在吗?

别看在吗很烦,至少能确定你们俩还是好友,要不他把你拉黑了你还不知道(有点跑题了)

如果超过10秒服务端还没回复“pong”,则认为连接断开的

我擦,敢删我好友,我这东北爷们的暴脾气这能忍?我把你也删了 。。。。。。。。。。。然后赶紧重新申请好友

这是暴脾气的客户端直接把连接关闭,调用closeSocket,可是一关闭我们的onSocketClose事件又去重连了(渣男)

至此,心跳重连实现完毕

总结

Socket心跳重连在H5中可以有类似的实现,也有成熟的第三方库,比如说stomp+websocket+sockjs可以实现更加完整的更兼容的socket连接方案,可以下次给大家分享(看我心情)。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Prototype String对象 学习
Jul 19 Javascript
javascript Array.sort() 跨浏览器下需要考虑的问题
Dec 07 Javascript
jquery实现网站超链接和图片提示效果
Mar 21 Javascript
jQuery ui 利用 datepicker插件实现开始日期(minDate)和结束日期(maxDate)
May 22 Javascript
JavaScript中的Math.SQRT1_2属性使用简介
Jun 14 Javascript
利用Node.js编写跨平台的spawn语句详解
Feb 12 Javascript
webpack学习教程之publicPath路径问题详解
Jun 17 Javascript
js 索引下标之li集合绑定点击事件
Jan 12 Javascript
angular 组件通信的几种实现方式
Jul 13 Javascript
Vue slot用法(小结)
Oct 22 Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
Dec 22 Javascript
node+multer实现图片上传的示例代码
Feb 18 Javascript
前端axios下载excel文件(二进制)的处理方法
Jul 31 #Javascript
JS构造一个html文本内容成文件流形式发送到后台
Jul 31 #Javascript
vue导出html、word和pdf的实现代码
Jul 31 #Javascript
JavaScript函数节流和函数去抖知识点学习
Jul 31 #Javascript
JS使用遮罩实现点击某区域以外时弹窗的弹出与关闭功能示例
Jul 31 #Javascript
微信网页授权并获取用户信息的方法
Jul 30 #Javascript
axios简单实现小程序延时loading指示
Jul 30 #Javascript
You might like
php 保留小数点
2009/04/21 PHP
CodeIgniter CLI模式简介
2014/06/17 PHP
thinkphp的静态缓存用法分析
2014/11/29 PHP
php+ajax实现无刷新数据分页的办法
2015/11/02 PHP
Zend Framework动作助手Json用法实例分析
2016/03/05 PHP
如何实现JS函数的重载
2006/09/22 Javascript
jQuery调用RESTful WCF示例代码(GET方法/POST方法)
2014/01/26 Javascript
原生javascript实现Tab选项卡切换功能
2015/01/12 Javascript
jQuery+AJAX实现遮罩层登录验证界面(附源码)
2020/09/13 Javascript
基于jQuery实现网页打印功能
2015/12/01 Javascript
Angular.js中$apply()和$digest()的深入理解
2016/10/13 Javascript
值得分享的Bootstrap Table使用教程
2016/11/23 Javascript
Vue Spa切换页面时更改标题的实例代码
2017/07/15 Javascript
three.js加载obj模型的实例代码
2017/11/10 Javascript
微信小程序返回上一页传参并刷新过程解析
2019/12/13 Javascript
Vue之封装公用变量以及实现方式
2020/07/31 Javascript
js实现3D旋转效果
2020/08/18 Javascript
python学习笔记:字典的使用示例详解
2014/06/13 Python
Python threading多线程编程实例
2014/09/18 Python
Python实现把回车符\r\n转换成\n
2015/04/23 Python
python清除字符串里非字母字符的方法
2015/07/02 Python
python实现各进制转换的总结大全
2017/06/18 Python
Flask框架Jinjia模板常用语法总结
2018/07/19 Python
Ubuntu18.04中Python2.7与Python3.6环境切换
2019/06/14 Python
python禁用键鼠与提权代码实例
2019/08/16 Python
Python爬虫定时计划任务的几种常见方法(推荐)
2021/01/15 Python
Python中正则表达式对单个字符,多个字符和匹配边界等使用
2021/01/27 Python
英国在线房屋中介网站:Yopa
2018/01/09 全球购物
TecoBuy澳大利亚:在线电子和小工具商店
2020/06/25 全球购物
个人简历自我评价
2014/01/06 职场文书
原材料检验岗位职责
2014/03/15 职场文书
空气环保标语
2014/06/12 职场文书
意外伤害赔偿协议书
2014/09/16 职场文书
2015年学校总务处工作总结
2015/05/19 职场文书
教你用Java Swing实现自助取款机系统
2021/06/11 Java/Android
MySQL索引失效十种场景与优化方案
2023/05/08 MySQL