Skip to content

前端创建一个 WebSocket 客户端

这里提供一个简单的 WebSocket 客户端示例,用于连接到 WebSocket 服务器并发送和接收消息。

js
// websocketClient.js

/** 默认的事件回调函数 */

/**
 * 默认的消息回调函数
 * @param {string} message - 接收到的消息内容
 */
function defaultOnMessage(message) {
    console.log('[wss] : 接收到消息:', message)
}

/** 默认的连接成功回调函数 */
function defaultOnOpen() {
    console.log('[wss] : 连接已建立')
}

/** 默认的连接关闭回调函数 */
function defaultOnClose() {
    console.log('[wss] : 连接已关闭')
}

/**
 * 默认的错误回调函数
 * @param {ErrorEvent} e - 错误事件
 */
function defaultOnError(e) {
    console.error('[wss] : 连接出错:', e)
}

/** 默认重连间隔 */
const defaultReconnectInterval = 3000

export class WebSocketClient {
    /**
     * 创建 WebSocket 客户端实例
     * @param {string} url - WebSocket 服务器地址,如 ws://localhost:3000
     * @param {Object} [options] - 可选配置项
     * @param {function(string):void} [options.onMessage] - 收到消息时的回调函数
     * @param {function():void} [options.onOpen] - 连接建立时的回调
     * @param {function():void} [options.onClose] - 连接关闭时的回调
     * @param {function(ErrorEvent):void} [options.onError] - 连接出错时的回调
     * @param {number} [options.reconnectInterval=3000] - 重连间隔(毫秒)
     */
    constructor(url, options = {}) {
        this.url = url

        // 用户自定义事件回调,提供默认回调以便于调试
        this.onMessage = options.onMessage || defaultOnMessage
        this.onOpen = options.onOpen || defaultOnOpen
        this.onClose = options.onClose || defaultOnClose
        this.onError = options.onError || defaultOnError

        // 可选配置项(重连、心跳)
        this.reconnectInterval = options.reconnectInterval || defaultReconnectInterval

        this.wsc = null
        this.connected = false

        this.reconnectTimer = null

        this.messageQueue = []

        this.connect()  // 立即发起连接
    }

    /** 建立 WebSocket 连接 */
    connect() {
        this.wsc = new WebSocket(this.url)

        this.wsc.onopen = () => {
            this.connected = true
            this.onOpen()

            this.flushMessageQueue()  // 发送缓存中的消息
        }

        this.wsc.onmessage = (event) => {
            // 执行用户定义的消息处理逻辑
            this.onMessage(event.data)
        }

        this.wsc.onclose = () => {
            this.connected = false
            this.onClose()
            this.scheduleReconnect() // 尝试重连
        }

        this.wsc.onerror = (e) => {
            this.onError(e)
            this.wsc.close() // 主动关闭触发重连逻辑
        }
    }

    /** 安排重连逻辑(防止多次重复触发) */
    scheduleReconnect() {
        if (this.reconnectTimer) return

        this.reconnectTimer = setTimeout(() => {
            console.log('[wss] : 尝试重连...')
            this.reconnectTimer = null
            this.connect()
        }, this.reconnectInterval)
    }

    /**
     * 发送消息,如果未连接则加入缓存队列
     * @param {string} message - 要发送的消息内容
     */
    send(message) {
        if (this.connected) {
            this.wsc.send(message)
        } else {
            this.messageQueue.push(message)
        }
    }

    /** 将缓存队列中的消息一一发出 */
    flushMessageQueue() {
        while (this.messageQueue.length > 0 && this.connected) {
            const msg = this.messageQueue.shift()
            this.wsc.send(msg)
        }
    }

    /** 主动关闭连接并清理资源 */
    close() {
        if (this.reconnectTimer) clearTimeout(this.reconnectTimer)

        this.wsc.close()
        this.connected = false
    }
}