您好,小程序模板欢迎您。
小程序模板
当前位置 : 首页> 小程序教程> 如何处理微信小程序中WebSocket连接断开的情况?

如何处理微信小程序中WebSocket连接断开的情况?

微信小程序中 WebSocket 连接断开是常见场景(如网络波动、服务器重启、小程序切后台),核心处理思路是 **“监听断开事件 + 优雅重连 + 消息保障”**,确保连接稳定性和数据不丢失。以下是具体实现方案:


### 一、先明确:连接断开的常见原因

1. 网络异常(Wi-Fi 切换、4G/5G 断网);

2. 服务器主动关闭连接(如超时、维护);

3. 小程序切后台超过 5-10 秒(微信会冻结网络连接);

4. 发送频率过高、消息过大触发系统限流,导致连接被强制关闭;

5. 设备休眠、网络信号弱导致连接超时。


### 二、核心处理步骤

#### 1. 监听断开事件:捕获断开状态

通过 `wx.onSocketClose` 监听连接断开,获取断开原因(如错误码),为后续处理提供依据。


```javascript

// 监听 WebSocket 连接关闭事件

wx.onSocketClose((res) => {

  console.log('WebSocket 连接已断开', res);

  // res 包含两个关键参数:

  // code: 关闭状态码(1000 表示正常关闭,1006 表示异常断开,其他为系统错误码)

  // reason: 关闭原因描述(字符串)


  // 区分正常关闭和异常断开

  if (res.code !== 1000) {

    console.log('异常断开,准备重连');

    // 执行重连逻辑

    this.startReconnect();

  } else {

    console.log('正常关闭(如主动调用 closeSocket),无需重连');

  }

});


// 同时监听连接错误(错误会导致断开,需同步处理)

wx.onSocketError((err) => {

  console.error('WebSocket 连接错误,即将断开', err);

  // 错误发生后,连接会自动关闭,需触发重连

  this.startReconnect();

});

```


#### 2. 实现优雅重连:避免频繁重试

重连的核心是 **“指数退避策略”**(重试间隔逐渐变长),避免短时间内频繁重试导致服务器压力过大,同时设置最大重试次数防止死循环。


##### (1)重连逻辑实现(含指数退避)

```javascript

Page({

  data: {

    reconnectCount: 0, // 已重试次数

    maxReconnectCount: 10, // 最大重试次数(避免无限重试)

    reconnectTimer: null, // 重试定时器(用于取消重试)

    isReconnecting: false // 避免重复触发重连

  },


  // 开始重连

  startReconnect() {

    // 避免重复重连、超过最大次数则停止

    if (this.data.isReconnecting || this.data.reconnectCount >= this.data.maxReconnectCount) {

      return;

    }


    this.setData({

      isReconnecting: true,

      reconnectCount: this.data.reconnectCount + 1

    });


    // 指数退避:重试间隔 = 2^n * 1000ms(n 为重试次数,最大 5 秒)

    const delay = Math.min(Math.pow(2, this.data.reconnectCount) * 1000, 5000);


    console.log(`第 ${this.data.reconnectCount} 次重连,延迟 ${delay}ms`);


    // 延迟重试(避免立即重试导致的网络拥堵)

    this.data.reconnectTimer = setTimeout(() => {

      this.connectWebSocket(); // 重新发起连接

    }, delay);

  },


  // 重新发起 WebSocket 连接(复用连接逻辑)

  connectWebSocket() {

    wx.connectSocket({

      url: 'wss://your-server.com/ws',

      header: {

        'Authorization': 'your-token' // 重新携带身份信息

      },

      success: () => {

        console.log('重连请求已发送');

      },

      fail: (err) => {

        console.error('重连请求失败', err);

        // 重连失败,继续触发下一次重试

        this.startReconnect();

      }

    });


    // 重连成功后,重置状态

    wx.onSocketOpen(() => {

      console.log('WebSocket 重连成功');

      this.setData({

        reconnectCount: 0,

        isReconnecting: false

      });

      clearTimeout(this.data.reconnectTimer); // 清除重试定时器


      // 重连成功后,恢复未发送的消息(后续步骤会讲)

      this.resendUnsentMessages();

    });

  },


  // 页面卸载时,清除定时器(避免内存泄漏)

  onUnload() {

    clearTimeout(this.data.reconnectTimer);

  }

});

```


##### (2)重连的关键优化

- **指数退避**:避免短时间内频繁重试(如第 1 次延迟 1 秒,第 2 次 2 秒,第 3 次 4 秒,最大 5 秒);

- **最大重试次数**:防止网络彻底不可用时无限重试(建议 10 次,约 1 分钟后停止);

- **避免重复重连**:用 `isReconnecting` 标记,防止同一时间触发多次重连;

- **携带身份信息**:重连时需重新传递 Token 等身份信息,否则服务器可能拒绝连接。


#### 3. 保障消息不丢失:未发送消息缓存

连接断开时,若有未发送成功的消息,需缓存到队列,重连成功后重新发送。


##### (1)实现消息队列与缓存

```javascript

Page({

  data: {

    messageQueue: [], // 待发送消息队列

    isSocketConnected: false // 连接状态标记

  },


  // 发送消息(统一通过队列管理)

  sendMessage(data) {

    if (this.data.isSocketConnected) {

      // 连接正常,直接发送

      wx.sendSocketMessage({

        data: JSON.stringify(data),

        success: () => {

          console.log('消息发送成功', data);

        },

        fail: (err) => {

          console.error('消息发送失败,加入队列', err);

          this.data.messageQueue.push(data); // 发送失败,加入队列

        }

      });

    } else {

      // 连接断开,直接加入队列

      console.log('连接已断开,消息加入队列');

      this.data.messageQueue.push(data);

    }

  },


  // 重连成功后,重新发送队列中的消息

  resendUnsentMessages() {

    if (this.data.messageQueue.length === 0) return;


    console.log(`重连成功,待发送消息数:${this.data.messageQueue.length}`);


    // 按顺序发送队列中的消息(搭配节流,避免发送频率过高)

    const sendNext = () => {

      if (this.data.messageQueue.length === 0) return;


      const data = this.data.messageQueue.shift();

      wx.sendSocketMessage({

        data: JSON.stringify(data),

        success: () => {

          console.log('队列消息发送成功', data);

          setTimeout(sendNext, 200); // 每条间隔 200ms,避免高频

        },

        fail: (err) => {

          console.error('队列消息发送失败,重新入队', err);

          this.data.messageQueue.unshift(data); // 失败后放回队首,下次重试

          setTimeout(sendNext, 1000); // 延迟 1 秒重试

        }

      });

    };


    sendNext();

  },


  // 监听连接状态变化,更新 isSocketConnected

  initSocketStatusListener() {

    wx.onSocketOpen(() => {

      this.setData({ isSocketConnected: true });

    });


    wx.onSocketClose(() => {

      this.setData({ isSocketConnected: false });

    });


    wx.onSocketError(() => {

      this.setData({ isSocketConnected: false });

    });

  }

});

```


#### 4. 特殊场景处理

##### (1)小程序切后台/前台

小程序切后台后,微信会冻结网络连接,导致 WebSocket 断开。需监听前后台切换,主动处理连接:


```javascript

// 监听小程序前后台切换

wx.onAppShow(() => {

  console.log('小程序切前台');

  // 检查连接状态,若断开则重连

  if (!this.data.isSocketConnected) {

    this.startReconnect();

  }

});


wx.onAppHide(() => {

  console.log('小程序切后台');

  // 可选:切后台时不主动关闭连接,但需做好重连准备

  // 若后台时间过长,连接会自动断开,前台时触发重连

});

```


##### (2)服务器主动关闭(如 Token 过期)

若服务器因 Token 过期、用户退出等原因主动关闭连接(`code` 非 1000 且有明确原因),需先处理业务逻辑(如重新登录),再重连:


```javascript

wx.onSocketClose((res) => {

  // 假设服务器返回 code = 401 表示 Token 过期

  if (res.code === 401) {

    console.log('Token 过期,需重新登录');

    // 1. 清除过期 Token

    wx.removeStorageSync('token');

    // 2. 跳转登录页

    wx.navigateTo({ url: '/pages/login/login' });

    // 3. 停止重连

    clearTimeout(this.data.reconnectTimer);

    this.setData({ isReconnecting: false });

    return;

  }


  // 其他异常断开,执行重连

  if (res.code !== 1000) {

    this.startReconnect();

  }

});

```


##### (3)网络状态监听

通过监听设备网络状态变化,在网络恢复时触发重连:


```javascript

// 监听网络状态变化

wx.onNetworkStatusChange((res) => {

  console.log('网络状态变化', res.isConnected);

  if (res.isConnected && !this.data.isSocketConnected && !this.data.isReconnecting) {

    console.log('网络恢复,触发重连');

    this.startReconnect();

  }

});

```


### 三、完整代码整合(可直接复用)

```javascript

Page({

  data: {

    isSocketConnected: false,

    messageQueue: [],

    reconnectCount: 0,

    maxReconnectCount: 10,

    reconnectTimer: null,

    isReconnecting: false

  },


  onLoad() {

    this.connectWebSocket();

    this.initSocketListeners();

  },


  // 初始化 WebSocket 连接

  connectWebSocket() {

    wx.connectSocket({

      url: 'wss://your-server.com/ws',

      header: {

        'Authorization': wx.getStorageSync('token') || ''

      }

    });

  },


  // 初始化所有监听器

  initSocketListeners() {

    // 连接成功

    wx.onSocketOpen(() => {

      console.log('WebSocket 连接成功');

      this.setData({

        isSocketConnected: true,

        reconnectCount: 0,

        isReconnecting: false

      });

      clearTimeout(this.data.reconnectTimer);

      this.resendUnsentMessages(); // 重发缓存消息

    });


    // 连接断开

    wx.onSocketClose((res) => {

      console.log('WebSocket 断开', res);

      this.setData({ isSocketConnected: false });

      if (res.code !== 1000) {

        this.startReconnect(); // 异常断开重连

      }

    });


    // 连接错误

    wx.onSocketError((err) => {

      console.error('WebSocket 错误', err);

      this.setData({ isSocketConnected: false });

      this.startReconnect();

    });


    // 接收消息(业务逻辑)

    wx.onSocketMessage((res) => {

      console.log('收到消息', res.data);

    });


    // 前后台切换

    wx.onAppShow(() => {

      if (!this.data.isSocketConnected) this.startReconnect();

    });


    // 网络状态变化

    wx.onNetworkStatusChange((res) => {

      if (res.isConnected && !this.data.isSocketConnected && !this.data.isReconnecting) {

        this.startReconnect();

      }

    });

  },


  // 发送消息(含队列缓存)

  sendMessage(data) {

    if (this.data.isSocketConnected) {

      wx.sendSocketMessage({

        data: JSON.stringify(data),

        fail: () => this.data.messageQueue.push(data)

      });

    } else {

      this.data.messageQueue.push(data);

    }

  },


  // 重发缓存消息

  resendUnsentMessages() {

    if (this.data.messageQueue.length === 0) return;

    const sendNext = () => {

      const data = this.data.messageQueue.shift();

      wx.sendSocketMessage({

        data: JSON.stringify(data),

        success: () => setTimeout(sendNext, 200),

        fail: () => {

          this.data.messageQueue.unshift(data);

          setTimeout(sendNext, 1000);

        }

      });

    };

    sendNext();

  },


  // 指数退避重连

  startReconnect() {

    if (this.data.isReconnecting || this.data.reconnectCount >= this.data.maxReconnectCount) return;

    this.setData({

      isReconnecting: true,

      reconnectCount: this.data.reconnectCount + 1

    });

    const delay = Math.min(Math.pow(2, this.data.reconnectCount) * 1000, 5000);

    this.data.reconnectTimer = setTimeout(() => this.connectWebSocket(), delay);

  },


  // 主动关闭连接(如退出页面)

  closeSocket() {

    wx.closeSocket();

    clearTimeout(this.data.reconnectTimer);

    this.setData({ isReconnecting: false });

  },


  onUnload() {

    this.closeSocket();

  }

});

```


### 四、关键注意事项

1. **避免死循环重连**:必须设置最大重试次数,防止网络彻底不可用时无限重试;

2. **消息去重**:若消息有唯一 ID,重发前需去重,避免重复发送(如服务器已收到但客户端未收到回调);

3. **服务器配合**:服务器需支持“重连后消息补发”(如客户端重连时请求未接收的消息),避免消息丢失;

4. **资源释放**:页面卸载、小程序退出时,主动关闭连接并清除定时器,避免内存泄漏;

5. **用户提示**:可选在连接断开时显示“连接已断开,正在重连...”,重连成功后隐藏,提升用户体验。


### 总结

处理 WebSocket 连接断开的核心是 **“监听断开 + 指数退避重连 + 消息队列缓存”**,同时适配前后台切换、网络变化等特殊场景,既保证连接稳定性,又避免数据丢失。以上方案可直接整合到小程序项目中,根据实际业务(如是否需要用户提示、消息优先级)调整细节即可。


联系客服 意见反馈

签到成功!

已连续签到1天,签到3天将获得积分VIP1天

知道了