websocket.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // websocket.js
  2. // 封装一个兼容多端的 uniapp WebSocket 管理类,支持自动重连与心跳机制,便于在uni-app项目中统一管理WebSocket连接
  3. class UniWebSocket {
  4. /**
  5. * 构造函数,初始化WebSocket管理器
  6. * @param {string} url - WebSocket服务器地址
  7. * @param {object} options - 可选配置项,如最大重连次数、心跳间隔等
  8. */
  9. constructor(url, options = {}) {
  10. this.url = url; // WebSocket服务器地址
  11. this.options = options; // 连接配置参数
  12. this.socketTask = null; // uni.connectSocket返回的socket任务对象
  13. this.isConnected = false; // 当前连接状态
  14. this.reconnectCount = 0; // 当前已重连次数
  15. this.maxReconnect = options.maxReconnect || 5; // 最大重连次数,默认5次
  16. this.heartbeatInterval = options.heartbeatInterval || 30000; // 心跳包发送间隔,默认30秒
  17. this.heartbeatTimer = null; // 心跳定时器
  18. this.eventListeners = {
  19. open: [], // 连接打开事件监听器
  20. message: [], // 消息接收事件监听器
  21. error: [], // 错误事件监听器
  22. close: [] // 关闭事件监听器
  23. };
  24. this.manualClose = false; // 是否为手动关闭连接
  25. }
  26. /**
  27. * 建立WebSocket连接
  28. * 若已连接则不重复连接
  29. */
  30. connect() {
  31. if (this.isConnected) return;
  32. this.manualClose = false;
  33. this.socketTask = uni.connectSocket({
  34. url: this.url,
  35. ...this.options
  36. });
  37. this._initEvent(); // 初始化事件监听
  38. }
  39. /**
  40. * 初始化WebSocket事件监听(open、message、error、close)
  41. * 绑定到socketTask对象
  42. * @private
  43. */
  44. _initEvent() {
  45. // 连接成功事件
  46. this.socketTask.onOpen = (res) => {
  47. this.isConnected = true;
  48. this.reconnectCount = 0;
  49. this._emit('open', res);
  50. this._startHeartbeat(); // 启动心跳
  51. };
  52. // 接收到消息事件
  53. this.socketTask.onMessage = (res) => {
  54. this._emit('message', res);
  55. this._startHeartbeat(); // 收到消息后重置心跳
  56. };
  57. // 连接错误事件
  58. this.socketTask.onError = (err) => {
  59. this._emit('error', err);
  60. this._reconnect(); // 尝试重连
  61. };
  62. // 连接关闭事件
  63. this.socketTask.onClose = (res) => {
  64. this.isConnected = false;
  65. this._emit('close', res);
  66. this._stopHeartbeat(); // 停止心跳
  67. if (!this.manualClose) {
  68. this._reconnect(); // 非手动关闭时自动重连
  69. }
  70. };
  71. }
  72. /**
  73. * 发送消息到WebSocket服务器
  74. * @param {string|object} data - 要发送的数据,支持字符串或对象
  75. * @returns {Promise} - 发送成功/失败的Promise
  76. */
  77. send(data) {
  78. return new Promise((resolve, reject) => {
  79. if (!this.isConnected) {
  80. reject('WebSocket 未连接');
  81. return;
  82. }
  83. this.socketTask.send({
  84. data: typeof data === 'string' ? data : JSON.stringify(data),
  85. success: resolve,
  86. fail: reject
  87. });
  88. });
  89. }
  90. /**
  91. * 主动关闭WebSocket连接
  92. * @param {number} code - 关闭码,默认1000
  93. * @param {string} reason - 关闭原因
  94. */
  95. close(code = 1000, reason = '') {
  96. this.manualClose = true;
  97. if (this.socketTask) {
  98. this.socketTask.close({ code, reason });
  99. }
  100. this._stopHeartbeat();
  101. }
  102. /**
  103. * 注册事件监听器
  104. * @param {string} event - 事件名(open/message/error/close)
  105. * @param {function} callback - 回调函数
  106. */
  107. on(event, callback) {
  108. if (this.eventListeners[event]) {
  109. this.eventListeners[event].push(callback);
  110. }
  111. }
  112. /**
  113. * 移除事件监听器
  114. * @param {string} event - 事件名
  115. * @param {function} callback - 需移除的回调函数
  116. */
  117. off(event, callback) {
  118. if (this.eventListeners[event]) {
  119. this.eventListeners[event] = this.eventListeners[event].filter(fn => fn !== callback);
  120. }
  121. }
  122. /**
  123. * 触发事件,调用所有注册的监听器
  124. * @param {string} event - 事件名
  125. * @param {any} data - 事件数据
  126. * @private
  127. */
  128. _emit(event, data) {
  129. if (this.eventListeners[event]) {
  130. this.eventListeners[event].forEach(fn => fn(data));
  131. }
  132. }
  133. /**
  134. * 自动重连逻辑,递增重连次数,超出最大次数则停止
  135. * @private
  136. */
  137. _reconnect() {
  138. if (this.reconnectCount < this.maxReconnect) {
  139. this.reconnectCount++;
  140. setTimeout(() => {
  141. this.connect();
  142. }, 1000 * this.reconnectCount); // 重连间隔递增
  143. }
  144. }
  145. /**
  146. * 启动心跳机制,定时发送ping包保持连接活跃
  147. * @private
  148. */
  149. _startHeartbeat() {
  150. this._stopHeartbeat();
  151. if (this.heartbeatInterval > 0) {
  152. this.heartbeatTimer = setInterval(() => {
  153. if (this.isConnected) {
  154. this.send('ping').catch(() => {});
  155. }
  156. }, this.heartbeatInterval);
  157. }
  158. }
  159. /**
  160. * 停止心跳机制
  161. * @private
  162. */
  163. _stopHeartbeat() {
  164. if (this.heartbeatTimer) {
  165. clearInterval(this.heartbeatTimer);
  166. this.heartbeatTimer = null;
  167. }
  168. }
  169. }
  170. export default UniWebSocket;