uniapp在APP上如何使用websocket--详解

UniApp 在 APP 端如何使用 WebSocket以及常见问题

一、WebSocket 基础概念

WebSocket 是一种在单个TCP连接上进行全双工通信的协议,适用于实时数据传输场景(如聊天室、实时游戏、股票行情等)。

与传统HTTP对比

特性WebSocketHTTP
连接方式长连接短连接
通信方向全双工半双工
数据格式二进制/文本文本
首部大小2-10字节8000+字节

二、UniApp 中使用 WebSocket

1. API 概览

UniApp 封装了微信小程序风格的 WebSocket API:

  • uni.connectSocket() - 创建连接
  • uni.onSocketOpen() - 监听连接打开
  • uni.onSocketError() - 监听错误
  • uni.sendSocketMessage() - 发送消息
  • uni.onSocketMessage() - 接收消息
  • uni.closeSocket() - 关闭连接
  • uni.onSocketClose() - 监听关闭

2. 完整使用示例

// websocket.js
let socketTask = null;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;

export function connectWebSocket() {
  return new Promise((resolve, reject) => {
    const url = 'wss://your-websocket-server.com';
    
    // 创建连接
    socketTask = uni.connectSocket({
      url: url,
      success: () => {
        console.log('WebSocket 连接创建中...');
      },
      fail: (err) => {
        console.error('连接创建失败:', err);
        reject(err);
      }
    });

    // 监听打开事件
    socketTask.onOpen((res) => {
      console.log('WebSocket 连接已打开');
      reconnectAttempts = 0;
      resolve(socketTask);
    });

    // 监听错误事件
    socketTask.onError((err) => {
      console.error('WebSocket 错误:', err);
      handleReconnection();
      reject(err);
    });

    // 监听关闭事件
    socketTask.onClose((res) => {
      console.log('WebSocket 连接已关闭', res);
      if (!res.code === 1000) { // 非正常关闭
        handleReconnection();
      }
    });
  });
}

function handleReconnection() {
  if (reconnectAttempts < maxReconnectAttempts) {
    reconnectAttempts++;
    const delay = Math.min(1000 * reconnectAttempts, 5000);
    
    console.log(`尝试第 ${reconnectAttempts} 次重连,${delay}ms后执行`);
    
    setTimeout(() => {
      connectWebSocket().catch(console.error);
    }, delay);
  } else {
    console.error(`已达到最大重连次数 ${maxReconnectAttempts}`);
  }
}

// 发送消息
export function sendWebSocketMessage(message) {
  return new Promise((resolve, reject) => {
    if (!socketTask || socketTask.readyState !== 1) {
      reject('WebSocket 未连接');
      return;
    }

    socketTask.send({
      data: JSON.stringify(message),
      success: () => resolve(),
      fail: (err) => reject(err)
    });
  });
}

// 关闭连接
export function closeWebSocket() {
  if (socketTask) {
    socketTask.close({
      code: 1000,
      reason: '用户主动关闭'
    });
  }
}

3. 心跳机制实现

let heartbeatTimer = null;

function startHeartbeat() {
  // 每30秒发送一次心跳
  heartbeatTimer = setInterval(() => {
    sendWebSocketMessage({
      type: 'heartbeat',
      timestamp: Date.now()
    }).catch(() => {
      clearInterval(heartbeatTimer);
    });
  }, 30000);
}

// 在onOpen中调用
socketTask.onOpen(() => {
  startHeartbeat();
});

// 在onClose中清除
socketTask.onClose(() => {
  clearInterval(heartbeatTimer);
});

4. 消息队列处理

当网络不稳定时,可实现消息队列:

let messageQueue = [];
let isSending = false;

async function processQueue() {
  if (isSending || messageQueue.length === 0) return;
  
  isSending = true;
  const message = messageQueue.shift();
  
  try {
    await sendWebSocketMessage(message);
  } catch (err) {
    messageQueue.unshift(message); // 重新放回队列
  } finally {
    isSending = false;
    processQueue();
  }
}

export function queueMessage(message) {
  messageQueue.push(message);
  processQueue();
}

三、注意事项

  1. 平台差异

    • iOS 对后台WebSocket连接限制严格
    • 部分安卓机型可能在锁屏后断开连接
  2. 安全要求

    • 必须使用wss协议(SSL加密)
    • 建议实现消息加密(如AES)
  3. 性能优化

    • 大数据量传输建议使用ArrayBuffer
    • 避免频繁发送小消息(可合并发送)
  4. 调试技巧

    // 开启调试模式
    uni.setEnableDebug({
      enableDebug: true
    });
    

四、完整页面示例

<template>
  <view class="container">
    <button @click="connect">连接WebSocket</button>
    <button @click="send">发送测试消息</button>
    <button @click="close">关闭连接</button>
    
    <scroll-view scroll-y class="message-box">
      <view v-for="(msg, index) in messages" :key="index">
        {{ msg }}
      </view>
    </scroll-view>
  </view>
</template>

<script>
import { connectWebSocket, sendWebSocketMessage, closeWebSocket } from '@/utils/websocket';

export default {
  data() {
    return {
      messages: [],
      socketTask: null
    }
  },
  onUnload() {
    closeWebSocket();
  },
  methods: {
    async connect() {
      try {
        this.socketTask = await connectWebSocket();
        
        this.socketTask.onMessage((res) => {
          this.messages.push('收到消息: ' + res.data);
        });
        
        this.messages.push('WebSocket 已连接');
      } catch (err) {
        this.messages.push('连接失败: ' + err);
      }
    },
    
    async send() {
      try {
        await sendWebSocketMessage({
          type: 'test',
          content: 'Hello WebSocket',
          timestamp: Date.now()
        });
        this.messages.push('消息已发送');
      } catch (err) {
        this.messages.push('发送失败: ' + err);
      }
    },
    
    close() {
      closeWebSocket();
      this.messages.push('已主动关闭连接');
    }
  }
}
</script>

<style>
.container {
  padding: 20px;
}
.message-box {
  height: 300px;
  margin-top: 20px;
  border: 1px solid #eee;
  padding: 10px;
}
</style>

五、常见问题解决

Q1: 安卓设备连接不稳定

  • 解决方案:在manifest.json中配置:

    "app-plus": {
      "keepRunning": true,
      "optimization": {
        "keepAlive": true
      }
    }
    

Q2: iOS后台断连

  • 解决方案:启用后台模式(需在manifest.json中声明):

    "ios": {
      "UIBackgroundModes": ["audio"]
    }
    

    并通过心跳保持活跃

Q3: 真机调试无法连接

  • 检查项:
    1. 是否使用HTTPS/WSS
    2. 域名是否加入白名单
    3. 手机网络是否正常

Q4: 如何发送二进制数据

// 发送ArrayBuffer
const buffer = new ArrayBuffer(8);
socketTask.send({
  data: buffer,
  fail: console.error
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值