uniapp封装websocket
WebSocket介绍
项目使用场景
开发uniapp项目时,需要进行实时通信,比如聊天等。需要封装一个工具类,统一对socket进行管理。
uniapp websocket官方文档:https://uniapp.dcloud.net.cn/api/request/websocket.html
代码解释
- 采用单例模式,业务直接引入。
- 主要是通过事件触发的形式,即收到特定事件,触发对应触发器,前端引入后,只需要添加相对应事件监听器即可。
注意:在收到数据时,已经默认使用JSON去解析了一次
代码
主要通过消息通信进行操作,这里定义了一个消息实体模板socketMessageTemplate
功能不齐全,大家按需使用,欢迎补充和讨论
// websocket.js
// 基础消息模板
const socketMessageTemplate = {type: "", // 消息类型timestamp: null, // 时间戳data: null, // 数据from: "", // 发送者to: "", // 接收者msg: "", // 消息内容
};// WebSocket 管理类
class WebSocketManager {constructor({// 最大重连次数maxReconnectAttempts = 3,// 重连间隔(毫秒)reconnectInterval = 5000,// 心跳间隔(毫秒)heartbeatInterval = 60000,} = {}) {this.socket = null; // WebSocket 实例this.listeners = {}; // 事件监听器this.status = "closed"; // 连接状态:closed, connecting, connectedthis.heartbeatTimer = null; // 心跳定时器this.reconnectAttempts = 0; // 当前重连次数this.maxReconnectAttempts = maxReconnectAttempts; // 最大重连次数this.reconnectInterval = reconnectInterval; // 重连间隔(毫秒)this.heartbeatInterval = heartbeatInterval; // 心跳间隔(毫秒)this.url = null; // WebSocket 地址this.isManualClose = false; // 是否为用户主动关闭}/*** 连接 WebSocket* @param {string} url WebSocket 地址* @param {function} successCallback 连接成功回调函数*/connect(url, successCallback = () => { }) {if (!url) {console.error("WebSocket 地址不能为空");return;}/* if (this.status === "connecting") {console.warn("WebSocket 正在连接中,请稍后再试");return;} */if (this.status === "connected") {console.warn("WebSocket 已连接,请勿重复连接");return;}this.url = url;this.status = "connecting";this.isManualClose = false; // 重置手动关闭标志this.socket = uni.connectSocket({url,success: () => {successCallback();console.log("WebSocket 连接请求已发送");},fail: (error) => {console.error("WebSocket 连接失败", error);this.status = "closed";this.handleReconnect();},});this.initEventHandlers();}/*** 初始化 WebSocket 事件*/initEventHandlers() {uni.onSocketOpen(() => {if (this.status === "connected") return; // 避免重复发送初始化消息console.log("WebSocket 连接成功");this.status = "connected";this.reconnectAttempts = 0;this.startHeartbeat();this.triggerEvent("open");});uni.onSocketMessage(({ data }) => {try {const message = JSON.parse(decodeURIComponent(data));this.triggerEvent("message", message);} catch (err) {console.error("消息解析失败", err);}});uni.onSocketError((err) => {console.error("WebSocket 错误", err);this.triggerEvent("error", err);});uni.onSocketClose(() => {console.log("WebSocket 已关闭");this.status = "closed";this.stopHeartbeat();this.triggerEvent("close");if (!this.isManualClose) {this.handleReconnect();}});}/*** 处理重连逻辑*/handleReconnect() {if (this.reconnectAttempts < this.maxReconnectAttempts) {this.reconnectAttempts++;console.log(`尝试第 ${this.reconnectAttempts} 次重连...`);this.status = "connecting";setTimeout(() => this.connect(this.url), this.reconnectInterval);} else {this.status = "fail";console.error("重连次数已达上限,停止重连");}}/*** 启动心跳机制*/startHeartbeat() {this.stopHeartbeat(); // 避免重复启动this.heartbeatTimer = setInterval(() => {if (this.status === "connected") {this.sendMessage({ type: "HEARTBEAT" });// console.log('心跳检测中...');}}, this.heartbeatInterval);}/*** 停止心跳机制*/stopHeartbeat() {if (this.heartbeatTimer) {clearInterval(this.heartbeatTimer);this.heartbeatTimer = null;}}/*** 添加事件监听器* @param {string} event 事件类型* @param {function} callback 回调函数*/addListener(event, callback) {if (!this.listeners[event]) {this.listeners[event] = [];}this.listeners[event].push(callback);}/*** 移除事件监听器* @param {string} event 事件类型* @param {function} callback 回调函数*/removeListener(event, callback) {if (this.listeners[event]) {this.listeners[event] = this.listeners[event].filter((cb) => cb !== callback);}}/*** 移除所有事件监听器*/removeAllListeners() {this.listeners = {}; // 清空所有事件监听器}/*** 触发事件* @param {string} event 事件类型* @param {any} data 回调数据*/triggerEvent(event, data = null) {(this.listeners[event] || []).forEach((callback) => callback(data));}/*** 发送消息 异步* @param {object} message 消息内容*/async sendMessageWithRetry(message, retryCount = 3, delayMs = 1000) {for (let attempt = 0; attempt < retryCount; attempt++) {if (this.status === "connected") {// 处理type类型全部改为大写message.type = message.type.toUpperCase();const payload = JSON.stringify({...socketMessageTemplate,...message,timestamp: Date.now(),});uni.sendSocketMessage({data: payload,success: () => {console.log("消息发送成功", payload)},fail: (err) => console.error("消息发送失败", err),});return;}console.warn(`WebSocket 未连接,重试中 (${attempt + 1}/${retryCount})...`);await new Promise((resolve) => setTimeout(resolve, delayMs));}console.error("多次尝试发送消息失败,WebSocket 未连接");}/*** 发送消息* @param {object} message 消息内容*/sendMessage(message) {if (this.status === "connecting") {console.error("WebSocket 正在连接中,无法发送消息");return;}if (this.status === "fail") {console.error("WebSocket 连接已失败,无法发送消息");return;}if (this.status !== "connected") {console.error("WebSocket 未连接,无法发送消息");this.handleReconnect(); // 如果未连接,尝试重连return;}message.type = message.type.toUpperCase();const payload = JSON.stringify({...socketMessageTemplate,...message,timestamp: Date.now(),});uni.sendSocketMessage({data: payload,success: () => {// console.log("消息发送成功", payload)},fail: (err) => {console.error("消息发送失败", err);},});}/*** 关闭 WebSocket 连接*/close() {if (this.status === "closed") {console.warn("WebSocket 未连接,无需关闭");return;}if (this.status === "fail" || this.status === "connecting") {console.warn("WebSocket 当前状态无法正常关闭,重置状态");this.status = "closed"; // 强制重置状态this.isManualClose = true;return;}this.isManualClose = true; // 设置为手动关闭uni.closeSocket({success: () => {console.log("WebSocket 连接已关闭");this.status = "closed";this.stopHeartbeat();this.removeAllListeners(); // 关闭时移除所有事件监听器},fail: (err) => console.error("关闭 WebSocket 失败", err),});}
}// 单例模式
const WebSocketInstance = new WebSocketManager();
export default WebSocketInstance;
举例
这里用uniapp 举例
<template><view class="container"><view><text>WebSocket 通信示例</text></view><view><button @click="connectWebSocket">连接 WebSocket</button><button @click="sendMessage">发送消息</button><button @click="closeWebSocket">关闭 WebSocket</button></view><view><text>接收到的消息:</text><text>{{ receivedMessage }}</text></view></view>
</template><script setup>
import { ref } from "vue";
import WebSocketInstance from "@/utils/websocket"; // 引入封装的 WebSocket 管理类
import { useWebSocket } from '@/utils/common';const { url } = useWebSocket(12345);// 接收到的消息
const receivedMessage = ref("");// 连接 WebSocket
const connectWebSocket = () => {WebSocketInstance.connect(url);// 添加事件监听WebSocketInstance.addListener("open", () => {// console.log("WebSocket 已连接");});WebSocketInstance.addListener("message", (data) => {// console.log("接收到消息:", data);receivedMessage.value = JSON.stringify(data);});WebSocketInstance.addListener("close", () => {// console.log("WebSocket 已关闭");});WebSocketInstance.addListener("error", (error) => {console.error("WebSocket 错误", error);});
};// 发送消息
const sendMessage = () => {WebSocketInstance.sendMessageWithRetry({type: "CHAT",from: "user1",to: "SYSTEM",msg: "你好,这是一条测试消息!",});
};// 关闭 WebSocket
const closeWebSocket = () => {WebSocketInstance.close();
};
</script><style>
.container {padding: 20px;
}button {margin: 10px 0;
}
</style>
WebSocket介绍
WebSocket是一种在Web浏览器和Web服务器之间进行实时双向通信的协议。与HTTP协议不同的是,WebSocket在建立连接后,不需要通过发起HTTP请求来获取数据,而是可以直接在连接上发送和接收数据。
WebSocket的特点包括以下几个方面:
- 实时性:WebSocket可以在客户端和服务器之间实时地发送消息,而不需要等待服务器响应或轮询。
- 双向通信:WebSocket支持客户端和服务器之间的双向通信,可以在任一方向上发送或接收消息。
- 高效性:WebSocket使用TCP协议作为传输层协议,相较于HTTP协议,可以减少通信的开销和延迟。
- 跨域支持:WebSocket通过在HTTP握手过程中发送特定的头部信息来支持跨域通信。
- 推送功能:WebSocket支持服务器主动向客户端推送消息,不再需要客户端主动发送请求。
WebSocket的工作原理是通过建立一个持久化的连接,使用HTTP协议完成初始的握手过程,然后通过升级协议从HTTP协议切换到WebSocket协议。一旦建立连接,客户端和服务器可以通过发送消息来进行通信,而不需要再次发送HTTP请求。
WebSocket在实时聊天、实时数据更新、实时游戏等场景中具有广泛应用。由于其高效的双向通信特性,WebSocket也在移动应用和物联网等领域得到了广泛的应用。
后端Websocket配合使用参考我博客其他文章,好久没写博文了
相关文章:
uniapp封装websocket
WebSocket介绍 后端使用的是springbootnetty做websocket的服务端,参考我其他博文 项目使用场景 开发uniapp项目时,需要进行实时通信,比如聊天等。需要封装一个工具类,统一对socket进行管理。 uniapp websocket官方文档࿱…...
【Linux】18.Linux进程控制(2)
文章目录 3. 进程程序替换3.1 单进程版 -- 看看程序替换3.2 替换原理3.3 替换函数函数解释命名理解 3.4 多进程版 -- 验证各种程序替换接口3.5 自定义shell 3. 进程程序替换 3.1 单进程版 – 看看程序替换 makefile mycommand:mycommand.cgcc -o $ $^ -stdc99 .PHONY:clean …...
reactor框架使用时,数据流请求流程
1. 我们在Flux打开时,可以看到 public abstract class Flux<T> implements CorePublisher<T> { 2. public interface CorePublisher<T> extends Publisher<T> {void subscribe(CoreSubscriber<? super T> subscriber); } Publish…...
读西瓜书的数学准备
1,高等数学:会求偏导数就行 2,线性代数:会矩阵运算就行 参考:线性代数--矩阵基本计算(加减乘法)_矩阵运算-CSDN博客 3,概率论与数理统计:知道啥是随机变量就行...
摄像头模块如何应用在宠物产品领域
一、宠物监控类产品 家庭宠物远程监控摄像头 1.基本功能与原理:这类摄像头可以通过 Wi - Fi 连接到家庭网络,主人可以使用手机应用程序在任何有网络连接的地方查看宠物的实时画面。摄像头模块内置有图像传感器,能够捕捉光线并将其转换为数字…...
c++学习第七天
创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。 提示:以下是本篇文章正文内容,下面案例可供参考。 一、const成员函数 //Date.h#pragma once#include<iostream> using namespace std;class Date { public:Date…...
Ubuntu 24.04 LTS 通过 docker 安装 nextcloud 搭建个人网盘
准备 Ubuntu 24.04 LTSUbuntu 空闲硬盘挂载Ubuntu 安装 Docker DesktopUbuntu 24.04 LTS 安装 tailscale [我的Ubuntu服务器折腾集](https://blog.csdn.net/jh1513/article/details/145222679。 安装 nextcloud 参考 Ubuntu24.04系统Docker安装NextcloudOnlyoffice _。 更…...
RabbitMQ1-消息队列
目录 MQ的相关概念 什么是MQ 为什么要用MQ MQ的分类 MQ的选择 RabbitMQ RabbitMQ的概念 四大核心概念 RabbitMQ的核心部分 各个名词介绍 MQ的相关概念 什么是MQ MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出&am…...
Open3D计算点云粗糙度(方法一)【2025最新版】
目录 一、Roughness二、代码实现三、结果展示博客长期更新,本文最近更新时间为:2025年1月18日。 一、Roughness 通过菜单栏的Tools > Other > Roughness找到该功能。 这个工具可以估计点云的“粗糙度”。 选择一个或几个点云,然后启动这个工具。 CloudCompare只会询问…...
算法6(力扣148)-排序链表
1、问题 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 2、采用例子 输入:head [4,2,1,3] 输出:[1,2,3,4] 3、实现思路 将链表拆分成节点,存入数组使用sort排序,再用reduce重建链接 4、具…...
一文大白话讲清楚webpack基本使用——9——预加载之prefetch和preload以及webpackChunkName的使用
文章目录 一文大白话讲清楚webpack基本使用——9——预加载之prefetch和preload1. 建议按文章顺序从头看,一看到底,豁然开朗2. preload和prefetch的区别2. prefetch的使用3. preload的使用4. webpackChunkName 一文大白话讲清楚webpack基本使用——9——…...
【大数据2025】MapReduce
MapReduce 基础介绍 起源与发展:是 2004 年 10 月谷歌发表的 MAPREDUCE 论文的开源实现,最初用于大规模网页数据并行处理,现成为 Hadoop 核心子项目之一,是面向批处理的分布式计算框架。基本原理:分为 map 和 reduce …...
Windows图形界面(GUI)-QT-C/C++ - Qt List Widget详解与应用
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 QListWidget概述 使用场景 常见样式 QListWidget属性设置 显示方式 (Display) 交互行为 (Interaction) 高级功能 (Advanced) QListWidget常见操作 内容处理 增加项目 删除项目…...
深度学习python基础(第二节) 分支语句和循环语句
本节主要介绍分支语句和循环语句的基本语法。 注意:在python中的作用域以缩进为准。有语言基础的很好理解,了解语法格式就可以。 布尔类型和比较运算符 # True真,False假 a True print(f"布尔变量a的内容是:{a},类型是:{type(a)}") 比较运算…...
Gin 源码概览 - 路由
本文基于gin 1.1 源码解读 https://github.com/gin-gonic/gin/archive/refs/tags/v1.1.zip 1. 注册路由 我们先来看一段gin代码,来看看最终得到的一颗路由树长啥样 func TestGinDocExp(t *testing.T) {engine : gin.Default()engine.GET("/api/user", f…...
第6章 ThreadGroup详细讲解(Java高并发编程详解:多线程与系统设计)
1.ThreadGroup 与 Thread 在Java程序中, 默认情况下, 新的线程都会被加入到main线程所在的group中, main线程的group名字同线程名。如同线程存在父子关系一样, Thread Group同样也存在父子关系。图6-1就很好地说明了父子thread、父…...
CentOS 7乱码问题如何解决?
1.使用超级用户操作: sudo su2.修改i18n配置文件: vi /etc/sysconfig/i18n将文件修改或添加为以下内容: LANG"zh_CN.UTF8" LC_ALL"zh_CN.UTF8"保存并退出(按Esc键,输入:wq,然后回车)…...
JavaScript语言的多线程编程
JavaScript语言的多线程编程 JavaScript是一种广泛使用的编程语言,主要用于网页开发。由于其单线程的特性,JavaScript 一直以来都有“无法进行多线程编程”的印象。尽管如此,随着技术的发展,JavaScript也逐渐引入了多线程的概念&…...
OpenSeaOtter使用手册-变更通知和持续部署
我们在OpenSeaOtter Server 0.1.1版本增加的镜像变更通知功能。通过镜像变更通知和OpenSeaOtter Agent就可以轻松获得持续部署能力。 镜像变更通知是通过push的方式下发到Agent的,Agent所在机器不需要外网地址。在Agent收到镜像变更通知后,就会调用对应的…...
(2)STM32 USB设备开发-USB虚拟串口
例程:STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com 本篇为USB虚拟串口教程,没有知识,全是实操,按照步骤就能获得一个STM32的USB虚拟串口。本例子是在野火F103MINI开发板上验证的,如果代码中出现一些外设的…...
Kandinsky-5.0-I2V-Lite-5s惊艳案例分享:宠物/人像/产品图5秒动态化成果集
Kandinsky-5.0-I2V-Lite-5s惊艳案例分享:宠物/人像/产品图5秒动态化成果集 1. 开篇:让静态图片动起来的魔法 你有没有想过,随手拍的照片能自己动起来?Kandinsky-5.0-I2V-Lite-5s就是这样一个神奇的AI工具。它能把你的宠物照片、…...
Python中正则表达式详解——从入门到精通,这一篇就够了!
目录 一、正则表达式是什么? 1.1 一个生活化的理解 1.2 正则表达式能做什么? 1.3 开始前的准备 二、正则表达式基础语法 2.1 元字符详解 2.2 预定义字符集(简化写法) 2.3 理解“贪婪”与“非贪婪” 三、re模块常用函数 …...
如何评估网站SEO优化的合理价格
如何评估网站SEO优化的合理价格 在当今数字化时代,网站的SEO优化已经成为提升网站流量和品牌知名度的关键因素。很多人在考虑投入网站SEO优化的时候,往往对其合理价格感到困惑。如何评估网站SEO优化的合理价格呢?本文将从多个角度为你详细解…...
Arduino_QTouch库深度解析:AVR电容触摸驱动原理与工业实践
1. Arduino_QTouch 库深度解析:面向嵌入式工程师的 Qtouch 电容式触摸传感器驱动实践指南Atmel(现为 Microchip)Qtouch 技术是工业级电容式触摸感应方案的标杆之一,其核心优势在于高抗噪性、低功耗、强环境适应性及无需覆盖层的裸…...
Arduino轻量级CLI库cmdArduino原理与实战
1. 项目概述cmdArduino 是一个面向 Arduino 平台的轻量级命令行接口(CLI)库,由 Freaklabs 团队的 Akiba 与 Jacinta 开发。其核心定位并非构建功能完备的嵌入式 Shell(如 BusyBox 或 MicroPython REPL),而是…...
Block Diffusion【202503】:在自回归与扩散语言模型之间插值【Interpolating Between Autoregressive and Diffusion LM】
块扩散:在自回归与扩散语言模型之间插值 Marianne Arriola† ∗ Aaron Kerem Gokaslan† Justin T. Chiu‡ Zhihan Yang† Zhixuan Qi† Jiaqi Han Subham Sekhar Sahoo† Volodymyr Kuleshov† 摘要 扩散语言模型因其并行生成和可控性的潜力,相比自回归模型具有独特…...
边缘计算与云原生集成:构建智能边缘系统
边缘计算与云原生集成:构建智能边缘系统 前言 作为一个在数据深渊里捞了十几年 Bug 的女码农,我深知边缘计算在现代 IT 架构中的重要性。随着物联网设备的爆发式增长和 5G 技术的普及,边缘计算已经成为云计算的重要补充,为实时数据…...
三步掌握Alienware终极控制权:AlienFX Tools新手完全指南
三步掌握Alienware终极控制权:AlienFX Tools新手完全指南 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 你是否厌倦了Alienware官方软件的…...
黑苹果配置终极指南:用OpCore-Simplify工具30分钟搞定OpenCore EFI
黑苹果配置终极指南:用OpCore-Simplify工具30分钟搞定OpenCore EFI 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的黑苹果配置…...
证件照 API 怎么选?2026 年主流方案深度对比 + Python / Java / PHP 对接示例
一、2026 年新常态:AI 大模型正在重塑证件照服务入口 2026 年,用户获取服务的方式发生了根本变化。过去大家打开百度搜索“证件照制作”,现在更多人直接问文心一言、豆包、Kimi:“哪里可以快速生成合规证件照?” 据最…...
