- WebSocket是一种在
Web 应用程序中提供双向通信 的协议。它允许服务器和客户端之间建立持久 的连接,实现实时数据传输。相比传统的HTTP请求,WebSocket具有更低的延迟 和更高的效率 。 - WebSocket使用了一种新的
特殊的 协议头,在客户端和服务器之间进行握手,建立连接后,可以通过发送消息进行双向通信。这使得服务器能够主动向客户端推送数据,而不需要客户端发起请求。 - WebSocket可以在浏览器中使用,也可以在服务器端使用。在浏览器中,你可以使用JavaScript的 WebSocket API 来创建WebSocket连接,并处理接收和发送的消息。在服务器端,你可以使用相应的编程语言库或框架提供的WebSocket实现来创建和管理WebSocket连接。
- WebSocket在很多应用场景中都非常有用,比如实时聊天应用、实时数据更新、多人协作和实时游戏等。它提供了一种
高效 、可靠 和实时 的通信方式,已经成为现代Web开发中常用的技术之一。
本文主要实现web端
websocket 封装及创建,框架以vue3 、pinia 、typescript 项目为例
实现
stores
extractStore.ts
import type { PiniaCustomStateProperties, StoreActions, StoreGeneric, StoreGetters, StoreState, } from "pinia"; import type { ToRefs } from "vue"; import { isReactive, isRef, toRaw, toRef } from "vue"; type Extracted<SS> = ToRefs< StoreState<SS> & StoreGetters<SS> & PiniaCustomStateProperties<StoreState<SS>> > & StoreActions<SS>; export function extractStore<SS extends StoreGeneric>( store: SS, ): Extracted<SS> { const rawStore = toRaw(store); const refs: Record<string, unknown> = {}; for (const [key, value] of Object.entries(rawStore)) { if (isRef(value) || isReactive(value)) { refs[key] = toRef(store, key); } else if (typeof value === "function") { refs[key] = value; } } return refs as Extracted<SS>; }
permission
state.ts
import { defineStore } from "pinia"; import { State } from "./permission-types"; interface State { ws: WebSocket | null; message: any; } export const usePermissionState = defineStore({ id: "permission.state", state: (): State => { return { ws: null, message: "", }; }, });
getters.ts
import { computed } from "vue"; import { defineStore } from "pinia"; import { usePermissionState } from "./state"; export const usePermissionGetters = defineStore("permission.getters", () => { const state = usePermissionState(); return { message: computed((): any => state.message), }; });
action.ts
import { defineStore } from "pinia"; import { usePermissionState } from "./state"; export const usePermissionActions = defineStore("permission.actions", () => { const state = usePermissionState(); const createWebsocket = async (): Promise<void> => { const ws = new WS(); state.ws = ws; state.ws.create(); }; const getWebsocketMsg = (payload: any): void => { state.message = payload; }; const sendWebsocketMsg = async ( payload: any, ): Promise<ReturnType<typeof getWebsocketMsg>> => { return getWebsocketMsg(payload); }; return { createWebsocket, sendWebsocketMsg, }; });
index.ts
import { extractStore } from "@/stores/extractStore"; import { defineStore } from "pinia"; import { usePermissionActions } from "./actions"; import { usePermissionGetters } from "./getters"; import { usePermissionState } from "./state"; export const usePermissionStore = defineStore("permission", () => { return { ...extractStore(usePermissionActions()), ...extractStore(usePermissionGetters()), ...extractStore(usePermissionState()), }; });
websocket
websocket-type.ts
export declare interface IWS { create(): void; send: (msg: any) => void; } export declare interface IConfig { url?: string; port?: number; protocol?: string; time?: number; } export declare type GetLocal = (key: string) => string;
websocket.ts
import { IWs, IConfig, GetLocal } from "./websocket-type"; import { usePermissionStore } from "@/stores/permission"; const permissionStore = usePermissionStore() const getLocal: GetLocal = (key) => { let value = localStorage.getItem(key) || ""; if (value.startsWith("[") || value.includes("{")) { return JSON.parse(value); } else { return value; } }; class WS implements IWs { private url: string; private port: number; private protocol: string; private time: number; private ws: null | WebSocket = null; private timer: null | ReturnType<typeof setTimeout> = null; constructor(config: IConfig = {}) { this.url = config.url || "localhost"; //路径 this.port = config.port || 4000; //端口号 this.protocol = config.protocol || "ws"; //协议 this.time = config.time || 30 * 1000; //心跳检测时间 } create() { this.ws = new WebSocket(`${this.protocol}://${this.url}:${this.port}`); this.ws.onopen = this.onOpen; //连接成功后事件 this.ws.onmessage = this.onMessage; //收到消息后事件 this.ws.onclose = this.onClose; //连接关闭事件 this.ws.onerror = this.onError; //连接异常事件 } private onOpen = () => { //发送消息 this.ws?.send( JSON.stringify({ //鉴权 type: "auth", data: getLocal("token"), }), ); }; private onMessage = (e: MessageEvent): void => { let { type, data } = JSON.parse(e.data); switch (type) { case "noAuth": console.log("没有权限"); break; case "heartCheck": //心跳检测 this.checkServer(); this.ws?.send( JSON.stringify({ type: "heartCheck", msg: "yes", }), ); break; default: permissionStore.sendWebsocketMsg(data) // 发送数据 } }; private onClose = (): void => { this.ws?.close(); }; private onError = (): void => { setTimeout(() => { this.create(); }, 1000); }; send = (msg: any) => { this.ws?.send(JSON.stringify(msg)); }; private checkServer(): void { this.timer && clearTimeout(this.timer); //防抖 this.timer = setTimeout(() => { this.onClose(); this.onError(); }, this.time + 1000); //断线重联 } } export default WS;
参考文档
- vue3
- pinia
- typescript
- WebSocket
- WebSocket 教程