前言

最近关于H5和APP的开发中使用到了webSocket,由于web/app有时候会出现网络不稳定或者服务端主动断开,这时候导致消息推送不了的情况,需要客户端进行重连。查阅资料后发现了一个心跳机制,也就是客户端间隔一段时间就向服务器发送一条消息,如果服务器收到消息就回复一条信息过来,如果一定时间内没有回复,则表示已经与服务器断开连接了,这个时候就需要进行重连。

被动断开则进行重连,主动断开的不重连。

说明:下图针对两个Tab项(Open Trades 和 Closed Trades),只希望在 tabIndex = 0 (Open Trades 高亮时)触发webSocket , 如果点击第二个栏目 , tabIndex = 1(Closed Trades高亮时)则主动关闭webSodket连接。

TabIndex = 0 时 ,被动断开则自动重连

原文链接:uni-app中websocket的使用 断开重连、心跳机制

效果

  1. webScoket连接并接收推送的消息

  2. 将接收的消息转换成目标数据,并渲染

  3. 如果主动关闭,则不进行重连,监听关闭事件

  4. 显示已关闭,不重连

  5. 监听错误事件,比如地址,协议错误等,则会自动重连五次,五次重连仍失败后则需要进行手动重连





  6. 如果服务端主动断开,心跳机制会每隔一段时间发送一条数据给服务端,如果没有回复则会进行webScoket重连。



代码

  1. 新建 socket.js , 将以下代码复制进去 ,向外暴露。
  1. import api from '@/common/js/config.js' // 接口Api,图片地址等等配置,可根据自身情况引入,也可以直接在下面url填入你的 webSocket连接地址
  2. class socketIO {
  3. constructor(data, time, url) {
  4. this.socketTask = null
  5. this.is_open_socket = false //避免重复连接
  6. this.url = url ? url : api.websocketUrl //连接地址
  7. this.data = data ? data : null
  8. this.connectNum = 1 // 重连次数
  9. this.traderDetailIndex = 100 // traderDetailIndex ==2 重连
  10. this.accountStateIndex = 100 // traderDetailIndex ==1 重连
  11. this.followFlake = false // traderDetailIndex == true 重连
  12. //心跳检测
  13. this.timeout = time ? time : 15000 //多少秒执行检测
  14. this.heartbeatInterval = null //检测服务器端是否还活着
  15. this.reconnectTimeOut = null //重连之后多久再次重连
  16. }
  17. // 进入这个页面的时候创建websocket连接【整个页面随时使用】
  18. connectSocketInit(data) {
  19. this.data = data
  20. this.socketTask = uni.connectSocket({
  21. url: this.url,
  22. success: () => {
  23. console.log("正准备建立websocket中...");
  24. // 返回实例
  25. return this.socketTask
  26. },
  27. });
  28. this.socketTask.onOpen((res) => {
  29. this.connectNum = 1
  30. console.log("WebSocket连接正常!");
  31. this.send(data)
  32. clearInterval(this.reconnectTimeOut)
  33. clearInterval(this.heartbeatInterval)
  34. this.is_open_socket = true;
  35. this.start();
  36. // 注:只有连接正常打开中 ,才能正常收到消息
  37. this.socketTask.onMessage((e) => {
  38. // 字符串转json
  39. let res = JSON.parse(e.data);
  40. console.log("res---------->", res) // 这里 查看 推送过来的消息
  41. if (res.data) {
  42. uni.$emit('getPositonsOrder', res);
  43. }
  44. });
  45. })
  46. // 监听连接失败,这里代码我注释掉的原因是因为如果服务器关闭后,和下面的onclose方法一起发起重连操作,这样会导致重复连接
  47. uni.onSocketError((res) => {
  48. console.log('WebSocket连接打开失败,请检查!');
  49. this.socketTask = null
  50. this.is_open_socket = false;
  51. clearInterval(this.heartbeatInterval)
  52. clearInterval(this.reconnectTimeOut)
  53. uni.$off('getPositonsOrder')
  54. if (this.connectNum < 6) {
  55. uni.showToast({
  56. title: `WebSocket连接失败,正尝试第${this.connectNum}次连接`,
  57. icon: "none"
  58. })
  59. this.reconnect();
  60. this.connectNum += 1
  61. } else {
  62. uni.$emit('connectError');
  63. this.connectNum = 1
  64. }
  65. });
  66. // 这里仅是事件监听【如果socket关闭了会执行】
  67. this.socketTask.onClose(() => {
  68. console.log("已经被关闭了-------")
  69. clearInterval(this.heartbeatInterval)
  70. clearInterval(this.reconnectTimeOut)
  71. this.is_open_socket = false;
  72. this.socketTask = null
  73. uni.$off('getPositonsOrder')
  74. if (this.connectNum < 6) {
  75. this.reconnect();
  76. } else {
  77. uni.$emit('connectError');
  78. this.connectNum = 1
  79. }
  80. })
  81. }
  82. // 主动关闭socket连接
  83. Close() {
  84. if (!this.is_open_socket) {
  85. return
  86. }
  87. this.socketTask.close({
  88. success() {
  89. uni.showToast({
  90. title: 'SocketTask 关闭成功',
  91. icon: "none"
  92. });
  93. }
  94. });
  95. }
  96. //发送消息
  97. send(data) {
  98. console.log("data---------->", data);
  99. // 注:只有连接正常打开中 ,才能正常成功发送消息
  100. if (this.socketTask) {
  101. this.socketTask.send({
  102. data: JSON.stringify(data),
  103. async success() {
  104. console.log("消息发送成功");
  105. },
  106. });
  107. }
  108. }
  109. //开启心跳检测
  110. start() {
  111. this.heartbeatInterval = setInterval(() => {
  112. this.send({
  113. "traderid": 10260,
  114. "type": "Ping"
  115. });
  116. }, this.timeout)
  117. }
  118. //重新连接
  119. reconnect() {
  120. //停止发送心跳
  121. clearInterval(this.heartbeatInterval)
  122. //如果不是人为关闭的话,进行重连
  123. if (!this.is_open_socket && (this.traderDetailIndex == 2 || this.accountStateIndex == 0 || this
  124. .followFlake)) {
  125. this.reconnectTimeOut = setInterval(() => {
  126. this.connectSocketInit(this.data);
  127. }, 5000)
  128. }
  129. }
  130. /**
  131. * @description 将 scoket 数据进行过滤
  132. * @param {array} array
  133. * @param {string} type 区分 弹窗 openposition 分为跟随和我的
  134. */
  135. arrayFilter(array, type = 'normal', signalId = 0) {
  136. let arr1 = []
  137. let arr2 = []
  138. let obj = {
  139. arr1: [],
  140. arr2: []
  141. }
  142. arr1 = array.filter(v => v.flwsig == true)
  143. arr2 = array.filter(v => v.flwsig == false)
  144. if (type == 'normal') {
  145. if (signalId) {
  146. arr1 = array.filter(v => v.flwsig == true && v.sigtraderid == signalId)
  147. return arr1
  148. } else {
  149. return arr1.concat(arr2)
  150. }
  151. } else {
  152. if (signalId > 0) {
  153. arr1 = array.filter(v => v.flwsig == true && v.sigtraderid == signalId)
  154. obj.arr1 = arr1
  155. } else {
  156. obj.arr1 = arr1
  157. }
  158. obj.arr2 = arr2
  159. return obj
  160. }
  161. }
  162. }
  163. module.exports = socketIO
  1. 在入口文件中 将 socketIO 挂载在 Vue 原型上 , 也可以按需引入置顶页面 。
  1. import socketIO from '@/common/js/scoket.js'
  2. Vue.prototype.socketIo = new socketIO()
  1. 在需要用到webSocket的页面中使用如下方法(可根据自身业务需求进行整改)
  1. scoketClose() {
  2. this.socketIo.connectNum = 1
  3. const data = {
  4. "value1": "demo1"
  5. "value2": "demo2"
  6. }
  7. this.socketIo.send(data) // 这是给后端发送特定数据 关闭推送
  8. this.socketIo.Close() // 主动 关闭连接 , 不会重连
  9. },
  10. getWebsocketData() {
  11. // 要发送的数据包
  12. const data = {
  13. "value": "value1",
  14. "type": "type1"
  15. }
  16. // 打开连接
  17. this.socketIo.connectSocketInit(data)
  18. // 接收数据
  19. uni.$on("getPositonsOrder", (res) => {
  20. this.connect = true
  21. const {
  22. Code,
  23. data
  24. } = res
  25. if (Code == xxxx) {
  26. // 根据后端传过来的数据进行 业务编写。。。
  27. } else {
  28. }
  29. })
  30. // 错误时做些什么
  31. uni.$on("connectError", () => {
  32. this.connect = false
  33. this.scoketError = true
  34. })
  35. }
  1. 离开页面,记得断开连接。
  1. onUnload() {
  2. this.scoketClose()
  3. this.socketIo.traderDetailIndex = 100 // 初始化 tabIndex
  4. }

遇到问题

如果在使用中遇到什么问题 ,可以给我留言 ,看到留言后会在第一时间进行回复 。

uni-app中websocket的使用 断开重连、心跳机制的更多相关文章

  1. uni app中使用自定义图标库

    项目中难免会用到自定义图标,那在uni app中应该怎么使用呢? 首先, 将图标目录放在static资源目录下: 在main.js中引入就可以全局使用了 import '@/static/icon-o ...

  2. uni app中关于图片的分包加载

    因为在项目中使用了大量的静态资源图片,使得主包体积过大, 而把这些图片全部放到服务器又有点麻烦,就想能不能把图片也分包,但是直接放在分包下的话导致图片资源找不到了, 在社区中看到大佬分享的十分有用,特 ...

  3. WebSocket断开原因、心跳机制防止自动断开连接

    1.断开原因 WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来. ws.onclose = function (e) { console.log('websocket ...

  4. fiddler 手机 https 抓包 以及一些fiddler无法解决的https问题http2、tcp、udp、websocket证书写死在app中无法抓包

    原文: https://blog.csdn.net/wangjun5159/article/details/52202059 fiddler手机抓包原理 fiddler手机抓包的原理与抓pc上的web ...

  5. java中websocket的应用

    在上一篇文章中,笔者简要介绍了websocket的应用场景及优点,戳这里 这篇文章主要来介绍一下在java项目中,特别是java web项目中websocket的应用. 场景:我做了一个商城系统,跟大 ...

  6. python 全栈开发,Day127(app端内容播放,web端的玩具,app通过websocket远程遥控玩具播放内容,玩具管理页面)

    昨日内容回顾 1. 小爬爬 内容采集 XMLY 的 儿童频道 requests 2. 登陆 注册 自动登陆 退出 mui.post("请求地址",{数据},function(){} ...

  7. Jmeter中Websocket协议支持包的使用

    Jmeter中Websocket协议支持包的使用(转) 参考的来源是国外一篇文章,已经整理成pdf格式(http://yunpan.cn/cFzwiyeQDKdh3 (提取码:9bcf)) 转自:ht ...

  8. Jmeter中Websocket协议支持包的使用(转)

    转自:http://blog.csdn.net/typing_yes_no/article/details/49512167 参考的来源是国外一篇文章,已经整理成pdf格式(http://yunpan ...

  9. Netty(六):Netty中的连接管理(心跳机制和定时断线重连)

    何为心跳 顾名思义, 所谓心跳, 即在TCP长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性. 为什么需要心跳 因为网络的不可靠性, 有可 ...

随机推荐

  1. C语言复习(二)

    引言: 不会将每一个部分都详述,只关注于一些自己认为重要的或常错的,若有不足,还望指出 switch()细节:括号内必须是整型或枚举类型:遇到break才会跳出:case包含的必须是常量 contin ...

  2. JavaGUI输入框事件监听的使用

    JavaGUI输入框事件监听的使用 package GUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt ...

  3. HTML5(十一)——WebSocket 基础教程

    一.为什么要学 WebSocket? websocket 是 HTML5 提供的一种长链接双向通讯协议,使得客户端和服务器之间的数据交换更简单,允许服务端主动向客户端推送数据,并且客户端与服务端只需连 ...

  4. VIM的跨行查找和匹配数量

    跨行用\n表示,例如 用4\n56可以匹配到: 4 56 中,查询一段文本中pattern出现的次数,类似于UltraEdit中的"Count All"功能,用:%s/patter ...

  5. 更换Swing界面中的窗口图标

    Swing 窗口图标更换 因为需要,所以要更改窗口的图标,很简单 在代码中加上 Image icon = Toolkit.getDefaultToolkit().getImage("图片地址 ...

  6. 【原创】Dubbo 2.7.8多个远程代码执行漏洞

    马上年底了,发现年初定的几个漏洞的KPI还没来得及完成,趁着最近有空赶紧突击一波,之前业务部门被爆过Dubbo的漏洞,干脆就把Dubbo拖过来挖一把.之前没用过Dubbo,既然要挖它就先大体了解了一下 ...

  7. git根据项目地址使用不同代理服务器

    问题 由于公司访问GitHub只能走代理,但是内网gitlab服务器又不能走代理. 因此想找到一种方案,可以支持git自动根据项目地址使用不同代理. 方案 如下所示,可以指定GitHub地址使用指定的 ...

  8. java JNI介绍

    java JNI介绍 目录 java JNI介绍 1. Java调用C++代码 2.C++代码调用java代码 JNI是Java Native Interface的全称. oracle文档中是这样描述 ...

  9. SQL 练习11

    查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息 SELECT * from Student WHERE SId in (SELECT SId from sc WHE ...

  10. 题解 Time

    传送门 首先枚举最大值,两边分别求逆序对的做法是错误的,这里是来自战神的hack数据 1 2 100 99 98 3 97 96 95 94 93 92 91 显然3应该跨过最大值到左边去,所以这个做 ...