使用vue3简单实现WebSocket通信

前端爆炸虫 2024-08-09 09:33:06 阅读 81

WebSocket是一种在客户端和服务器之间进行双向通信的网络协议。它通过建立持久性的、全双工的连接,允许服务器主动向客户端发送数据,而不需要客户端显式地发送请求。

关于WebSocket通信的简单介绍:

握手阶段:在建立WebSocket连接之前,客户端需要发送一个HTTP请求到服务器,请求升级为WebSocket协议。这个过程称为握手(Handshake)。如果服务器支持WebSocket协议,它将返回带有特定标头的HTTP响应,表示握手成功。建立连接:客户端收到服务器的握手响应后,会重新建立连接。此时,连接将从HTTP协议切换到WebSocket协议,并保持打开状态。这样就建立了可持续的双向通信通道。数据传输:一旦WebSocket连接建立,客户端和服务器可以开始互相发送消息。客户端和服务器都可以通过发送文本或二进制数据来通信。消息可以是简单的字符串,也可以是复杂的数据结构,如JSON对象等。断开连接:当需要关闭WebSocket连接时,客户端或服务器可以主动发送一个关闭帧来断开连接。收到关闭帧的一方会结束连接并发送回应帧,完成连接的关闭。

WebSocket通信具有以下特点:

实时性:由于WebSocket使用长连接,可以实时地将数据推送到客户端,而不需要显式地发送请求。这使得它非常适合需要快速、实时响应的应用程序。双向通信:WebSocket允许客户端和服务器之间双向传输消息。这意味着服务器可以主动向客户端推送数据,而不仅限于响应客户端的请求。较低的开销:相比于传统的轮询方式(每隔一段时间发送请求),WebSocket连接具有较低的开销。一旦建立连接,它只需要发送少量的数据头部信息,并且在保持连接时可以重复使用该连接。跨平台支持:WebSocket协议是一种标准化的协议,被广泛支持和应用于不同的平台和编程语言中。

通过使用WebSocket,开发人员可以实现实时通信、聊天应用、多人游戏、股票行情等需要及时交互和更新的应用程序。

1.相关代码如下:

①创建src/utils/websocket.ts文件

import { ElMessage } from 'element-plus'

import store from '../store'

let websocket: WebSocket | null = null; // 用于存储实例化后websocket

let rec: any; // 断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码

// 创建websocket

function creatWebSocket(wsUrl: string) {

console.log("websocket==================");

// 判断当前浏览器是否支持WebSocket

if ("WebSocket" in window) {

console.log("当前浏览器支持 WebSocket");

} else if ("MozWebSocket" in window) {

console.log("当前浏览器支持 MozWebSocket");

} else {

console.log("当前浏览器不支持 WebSocket");

}

try {

initWebSocket(wsUrl); // 初始化websocket连接

} catch (e) {

console.log("尝试创建连接失败");

reConnect(wsUrl); // 如果无法连接上 webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接

}

}

// 初始化websocket

function initWebSocket(wsUrl: string) {

websocket = new WebSocket(wsUrl);

console.log("websocket:", websocket);

websocket.onopen = function () {

websocketOpen();

};

// // 接收

websocket.onmessage = function (e: MessageEvent<any>) {

websocketonmessage(e);

};

// 连接发生错误

websocket.onerror = function () {

console.log("WebSocket连接发生错误");

// isConnect = false; // 连接断开修改标识

reConnect(wsUrl); // 连接错误 需要重连

};

websocket.onclose = function (e) {

websocketclose(e);

};

}

// 定义重连函数

let reConnect = (wsUrl: string) => {

console.log("尝试重新连接");

if (store.state.isConnected) return; // 如果已经连上就不在重连了

rec && clearTimeout(rec);

rec = setTimeout(function () {

// 延迟5秒重连 避免过多次过频繁请求重连

creatWebSocket(wsUrl);

}, 5000);

};

// 创建连接

function websocketOpen() {

console.log("连接成功");

store.dispatch('connect'); // 修改连接状态

}

// 数据接收

function websocketonmessage(e: MessageEvent<any>) {

console.log("数据接收", e.data);

const data = JSON.parse(e.data); // 解析JSON格式的数据

// 下面的判断则是后台返回的接收到的数据 如何处理自己决定

if (data.code === 400) {

console.log("数据接收", data.msg);

ElMessage({

showClose: true,

message: data.msg,

type: 'warning',

})

} else if (data.code === 404) {

ElMessage({

showClose: true,

message: data.msg,

type: 'warning',

})

} else if (data.code === 0) {

ElMessage({

showClose: true,

message: "连接成功",

type: 'success',

})

} else if (data.code === 200) {

ElMessage({

showClose: true,

message: data.msg,

type: 'success',

})

// 成功后的相应处理 此处成功后播放音乐

const audio = new Audio('./tipMusic.mp3');

audio.play();

} else {

ElMessage({

showClose: true,

message: data.msg,

type: 'error',

})

// 延时5秒后刷新页面

setTimeout(() => {

location.reload();

}, 1000);

}

// let data = JSON.parse(decodeUnicode(e.data))

}

// 关闭

function websocketclose(e: any) {

console.log(e);

store.dispatch('disconnect'); // 修改连接状态

console.log("connection closed (" + e.code + ")");

}

// 数据发送

function websocketsend(data: any) {

console.log("发送的数据", data, JSON.stringify(data));

if (websocket && store.state.isConnected) { // 检查连接状态

websocket.send(JSON.stringify(data));

} else {

ElMessage({

showClose: true,

message: "请选择设备连接",

type: 'error',

})

}

}

// 实际调用的方法==============

// 发送

function sendWebSocket(data: any) {

// 如果未保持连接状态 不允许直接发送消息 提示请选择连接设备

if (!store.state.isConnected) {

ElMessage({

showClose: true,

message: "请选择设备连接",

type: 'error',

})

} else {

websocketsend(data);

console.log("------------------");

}

}

// 关闭

let closeWebSocket = () => {

if (websocket) {

websocket.close();

ElMessage({

showClose: true,

message: "设备已关闭",

type: 'success',

})

}

};

export {

initWebSocket,

sendWebSocket,

creatWebSocket,

closeWebSocket,

};

②全局保存连接状态src/store/index.ts

先安装npm install vuex

import { createStore } from 'vuex'

const store = createStore({

state: {

isConnected: false,//连接状态

},

mutations: {

setConnected(state: any, isConnected: boolean) {

state.isConnected = isConnected

},

},

actions: {

connect({ commit }: { commit: any }) {

// 连接成功后,将 isConnected 状态设置为 true

commit('setConnected', true)

},

disconnect({ commit }: { commit: any }) {

// 断开连接或退出登录时,将 isConnected 状态设置为 false

commit('setConnected', false)

}

}

})

export default store

③页面连接设备

<script setup lang="ts">

import { ref ,onMounted} from 'vue'

import { closeWebSocket,initWebSocket } from '../../utils/websocket'

import { useStore } from 'vuex';

const store = useStore()

//连接设备 (具体路径和后端规定)

function connectMsg() {

const toIp = `ws://192.168.50.50:8822/websocket/ipad/${roomId.value}`;

store.dispatch('connect')

initWebSocket(toIp)

}

// 设备断开

function closeWs() {

closeWebSocket()

store.dispatch('disconnect')

}

</script>

<template>

<div class="connect">

          <el-button class="elbtn" @click="connectMsg">连接设备</el-button>

        <el-button class="elbtn" @click="closeWs">关闭设备</el-button>

        </div>

</template>

④发送消息给后端

<script setup lang="ts">

import {ref} from 'vue'

import { sendWebSocket } from '../../utils/websocket'

const courseTopic = ref('')

const courseGrowth = ref('')

const todayHaul = ref('')

const selectedTeacher = ref('')

//提交

const harvestSubmit = () => {

  // 要发送的数据  和后端定义格式

  const harvestData = {

    "HandlerType": "COURSEREFLECT",

    "topicReflect": courseTopic.value,

    "growReflect": courseGrowth.value,

    "harvest": todayHaul.value,

    "teacher": "李老师"

}

    console.log("提交反思与收获数据",harvestData); 

  // 发送消息给后端

    sendWebSocket(harvestData)

  

  }

</script>

<template>

        <div class="think">

          <p>课程反思</p>

        <el-input v-model="courseTopic" :rows="3" type="textarea" placeholder="主题课程" />

        <el-input v-model="courseGrowth" :rows="3" type="textarea" placeholder="适性成长课程" />

        <p>今日收获</p>

        <el-input v-model="todayHaul" :rows="3" type="textarea"  />

        </div>

        <div class="btn">

            <button @click="harvestSubmit"> 提交</button>

          </div>

    </template>

欢迎大家批评指正 谢谢 ~~



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。