前端WebSocket.ts工具类(token验证、代理配置、心跳检测)

上篇文章中提到了最近要做一个进度条的功能,但实际比进度条要复杂,有可能用在上传文件或者是服务端处理的进度或者是聊天助手等等,所以选择了用WebSocket。以下是我封装的WebSocket工具类及使用方案,目前还没有加上断线重连功能,后续会优化

包括的功能:
带有token验证 支持心跳检测 代理配置

工具类的封装

在units文件夹下新建一个叫WebsocketService.ts的文件

import {ElMessage} from 'element-plus';

/**
 * 消息状态
 * @enum 1000 连接已正常关闭
 * @enum 1001 终端离开或重新加载页面
 * @enum 1002 协议错误,无法解析收到的数据
 * @enum 1003 数据类型不符合要求
 * @enum 1006 连接已关闭,无法建立连接
 */

export default class WebsocketService {
    public readonly socket: any
    private readonly promises: any
    private isConnected: boolean | undefined // 连接状态
    private message: string | undefined // 消息内容
    private reconnectError: boolean | undefined// 重新连接错误
    private readonly heartBeatInterval: number | undefined// 心跳消息发送时间
    private heartBeatTimer: number | undefined // 心跳定时器
    private baseUrl: string | undefined //服务URL
    private readonly token: string | undefined

    constructor(connectUrl: string, onOpenCallback?: Function | undefined, onMessageCallback?: Function | undefined, onCloseCallback?: Function | undefined, onErrorCallback?: Function | undefined) {
        if (typeof WebSocket !== "undefined") {
            this.promises = {};
            this.isConnected = false
            this.message = ""
            this.reconnectError = false
            this.heartBeatInterval = 50000
            this.heartBeatTimer = 0
            this.baseUrl = (window.location.protocol.indexOf('https') !== -1 ? 'wss' : 'ws') + '://' + window.location.host + '/ws_proxy' //注意 ws_proxy是在vue.config.js单独配的 见下文
            this.token = window.sessionStorage.getItem("token") || ""
             // 这里通过子协议的方式将token传递给服务端,
             // 传递形式为:在请求的requestHeader中会有一个叫“Sec-Websocket-Protocol: 你的token串 ”的请求头
             // 在开发者工具中查看请求时注意筛选ws的请求,而不是Fetch/XHR
            this.socket = new window.WebSocket(this.baseUrl + connectUrl, [this.token])
            this.socket.onopen = (e: any) => this.handleOpen(this, e, onOpenCallback);
            this.socket.onmessage = (e: any) => this.handleMessage(this, e, onMessageCallback);
            this.socket.onclose = (e: any) => this.handleClose(this, e, onCloseCallback);
            this.socket.onerror = (e: any) => this.handleError(this, e, onErrorCallback);
        } else {
            ElMessage({
                message: "您的浏览器不支持WebSocket",
                type: 'error',
            })
        }
    }

    protected handleOpen(that: any, e: any, callBack?: Function | undefined) {
        that.isConnected = true
        that.heartBeatTimer = window.setInterval(() => {
            const message = 'keep heartbeat'
            that.sendMessage("heart_beat", message)
        }, that.heartBeatInterval);
        if (callBack) callBack(e)
    }

    protected handleMessage(that: any, e: any, callBack?: Function | undefined) {
        if (callBack) callBack(e)
    }

    protected handleClose(that: any, e: any, callBack?: Function | undefined) {
        that.isConnected = false
        clearInterval(this.heartBeatTimer)
        that.heartBeatTimer = 0
        that.socket.close()
        if (callBack) callBack(e)
    }

    protected close() {
        this.isConnected = false
        clearInterval(this.heartBeatTimer)
        this.heartBeatTimer = 0
        this.socket.close()
    }

    protected handleError(that: any, e: any, callBack: Function | undefined) {
        if (this.socket.readyState !== 3) {
            ElMessage({
                message: "连接异常,请尝试重新连接",
                type: 'error',
            })
        }
        if (callBack) callBack(e)
    }

    protected sendMessage(type: string, content: any) {
        this.socket.send(JSON.stringify({type: type, content: content}));
    }
}

业务页面使用方案

import socket from "@/utils/WebsocketService";
const progressPathName = "/ws" //你的服务端相对路径
const createProgressConnection = () => {
    progressSocket = new socket(progressPathName, undefined, onMessage, onClose, onError)
}
const onMessage = (e: any) => {
    const receivedData = JSON.parse(e.data.replace(new RegExp("\\\\\"", "gm"), "\"")) //反序列化服务端发送过来的消息
    const {type} = receivedData
    if (type === "xxx") { //拿到对应的第一条业务功能标识比如uuid等,因为你要区分业务逻辑啊
        window.sessionStorage.setItem("xxx", receivedData.xx) //将业务数据保存到本地,或者你自己的逻辑
        progressSocket.socket.send(JSON.stringify({
            ... //发送你的业务数据给服务端
        }))
    } else if (type === "XXX") {
        ... // todo something
    } else if (type === "close") {
        progressSocket.socket.close()
    }
}

const onError = () => {
    progressSocket.socket.close() // 或者你自己的逻辑
}

const onClose = (e: any) => {
    progressSocket.socket.close()
    let token = window.sessionStorage.getItem("token") || ""
    if (e.target && e.target.protocol === "") {
        // 验证失败
        ElMessage({
            message: "用户验证失败,请尝试重新登陆",
            type: 'error',
        })
    } else if (e.target && e.target.protocol === token) {
    }
}

代理配置之 vue.config.js

const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
    lintOnSave: false,
    transpileDependencies: true,
    devServer: {
        host: '127.0.0.1',
        port: 3001,
        open: true,
        proxy: {
            '/use_proxy': {
                target: process.env.VUE_APP_API_URL,
                pathRewrite: {'^/use_proxy': ''},
                ws: false,
                changeOrigin: true
            },
            '/ws_proxy': {
                target: process.env.VUE_APP_WS_URL,
                pathRewrite: {'^/ws_proxy': ''},
                ws: true,
                changeOrigin: true
            },
        }
    },
    configureWebpack: {
        devtool: 'source-map',
        optimization: {
            splitChunks: {
                chunks: 'all',
            },
        },
    },
})

代理配置之 .env

VUE_APP_API_URL=http://127.0.0.1:xxxx
VUE_APP_WS_URL=wss://xxx.xxx.com.cn //你的环境域名
// 注意:
// 1. wss是带有证书的WebSocket协议,这个结合实际来 
// 2. 正式环境是需要配置Nginx的

代理配置之 nginx.conf

...
server {
        listen       80;
        server_name  localhost;
        client_max_body_size 50M;

        location / {
		    root /usr/share/nginx/html/dist;
            try_files $uri $uri/ /index.html;
        }
        location /use_proxy/ {
            proxy_pass   https://xxx.com.cn;
            client_max_body_size 500M;
        }
        location /ws_proxy/ {
            proxy_pass   https://xxx.com.cn;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
   	}
...

本文原创,转载请注明出处

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
前端使用 WebSocket 进行心跳检测的方法如下: 1. 建立 WebSocket 连接:在前端代码中使用 WebSocket 对象创建与服务器的连接。例如: ```javascript const socket = new WebSocket('ws://example.com/socket'); socket.onopen = function() { // 连接建立后执行心跳检测 startHeartbeat(); }; socket.onclose = function() { // 连接关闭后停止心跳检测 stopHeartbeat(); }; ``` 2. 发送心跳消息:在心跳检测函数中,定期向服务器发送心跳消息。可以使用 `socket.send()` 方法发送一个特定的心跳消息,通常是一个空字符串或者一个特定的标识符。例如: ```javascript function sendHeartbeat() { socket.send(''); } ``` 3. 接收心跳回复:在服务器端收到心跳消息后,应该回复一个特定的消息给前端,表示服务器正常运行。前端可以通过监听 `socket.onmessage` 事件来接收服务器的回复。 ```javascript socket.onmessage = function(event) { if (event.data === 'heartbeat') { // 收到心跳回复,继续下一次心跳检测 startHeartbeat(); } }; ``` 4. 定时执行心跳检测:使用 `setInterval` 函数定时执行心跳检测函数。通常情况下,心跳间隔为几秒钟到几分钟之间。例如: ```javascript let heartbeatInterval; function startHeartbeat() { heartbeatInterval = setInterval(sendHeartbeat, 5000); // 每 5 秒发送一次心跳消息 } function stopHeartbeat() { clearInterval(heartbeatInterval); } ``` 通过以上步骤,前端可以通过 WebSocket 进行心跳检测,保持与服务器的连接状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厉害坤坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值