什么是websocket?
websocket,是web浏览器与web服务器之间全双工通信标准。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此 API,可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。

个人理解
1、http是浏览器主动的去进行连接,由服务器主动断开且只进行一次连接。
2、websocket是服务器或浏览器主动进行连接,断开连接是需要浏览器或服务器主动的断开,解决了http请求的单向连接,所以说websocket是双方各自进行断开或连接。

websocket简单示例

websocket的基础在这里不做过多阐述,详情可参考MDN对websocket的解释websocket

// 创建一个websocket连接.
const socket = new WebSocket('ws://localhost:8080');

// 监听连接成功
socket.addEventListener('open', function (event) {
    socket.send('Hello Server!');
});

// 监听返回的数据
socket.addEventListener('message', function (event) {
    console.log('Message from server ', event.data);
});

什么是websocket的心跳模式?
在进行开发的时候我们可能只是简单的运用websocket,但是有没有想过如果在进行连接的时候连接失败,如何判断是服务器主动断开连接还是请求连接失败呢?如果请求连接失败我们就断开连接吗?这是错的,我们应该去进行重连,在连接的时候加入判断如果服务器主动断开,我们关闭websocket连接,否则我们进行重连,设置一个定时重连,直到我们可以连接到服务器为止,这样做的话,不论是什么情况的断开连接我们都可以一一进行解决。

心跳模式的实现

var socket = null  // 申明socket,创建他的实例
var timeout = 1000 * 60; // 后端推送间隔为两分钟(待定)
var reconnectTimeout = 1000 * 60 * 2; // 尝试重连间隔为两分钟
var wsMap = new Map(); // ws 对象的集合库

/**
 * 初始化 props ,记录构建 socket 所提供的的信息,把成员挂载到 socket 的实例对象上
 * @param {*} socket 传入的 socket 实例
 * @param {*} onMessageCallback 收到数据时的回调函数,将数据传送给要接受的那个函数做处理
 * @param {*} wsKey 对应 socket 唯一的 key,指定唯一的访问地址
 */
function initProps(socket, onMessageCallback, wsKey) {
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    console.log(wsKey, socket);
    socket.onMessageCallback = onMessageCallback
    socket.wsKey = wsKey
    socket.timeout = null // 心跳定时器 
    socket.serverTimeout = null // 心跳反馈定时器
    // 这里保存上一个 ws 的重连状态,配合 reconnect 的节流功能,保存不会频繁发送无意义的心跳
	socket.debounceTimeout = wsMap.get(wsKey) ? wsMap.get(wsKey).debounceTimeout : null;
	wsMap.set(wsKey, socket); // 保存或者更新 ws 在资料库 map 的数据
}
/**
 * 开启心跳模式
 * @param {*} ws 传入的 socket 实例
 */
function start(ws) {
    ws.timeout = setTimeout(() => {
        // ws.send(JSON.stringify({type: 1000, data: 'HeartBeat'}))
        console.log("执行到这里了,start22222");
        ws.serverTimeout = setTimeout(() => {
            console.log("没有返回直接关闭");
            ws.close() // timeout 时间后没有返回,直接关闭此次连接
        }, timeout)
    }, timeout)
}
/**
 * 重连操作
 */
 function reconnect(ws) {
    // 节流
    clearTime(ws); // 如果发起重连,则关闭心跳等定时器
    const callNow = !ws.debounceTimeout;
    ws.debounceTimeout = setTimeout(() => {
        ws.debounceTimeout = null;
        reconnect(ws); // 已进行过重连的,下一次必须经过 reconnectTimeout 之后才能再次发起重连
    }, reconnectTimeout);
    if (callNow) {
        console.log("来到这里执行");
        initWebSocket(ws.url, ws.onMessageCallback, ws.wsKey);
    }
}
/**
 * 清除定时器
 */
 function clearTime(ws) {
    console.log(ws);
    ws.timeout && clearTimeout(ws.timeout)
    ws.serverTimeout && clearTimeout(ws.serverTimeout)
    ws.debounceTimeout && clearTimeout(ws.debounceTimeout)
}
/**
 * 重置心跳
 */
function reset(ws) {
    clearTime(ws)
    start(ws)
}
/**
 * 获取本地地址,代理的时候有用
 * @returns 本地的地址
 */
function getWebIP() {
    const curIP = window.location.host;
    return curIP;
}

/**
 * 收到服务器数据后的回调函数
 * @param {*} event websocket 发送来的数据
 * @param {*} onMessageCallback 收到数据时的回调函数,将数据传送给要接受的那个函数做处理
 */
function onMessage(event, onMessageCallback) {
    // 重置心跳
    reset(event.currentTarget)
    if(onMessageCallback) {
        try {
            let res = JSON.parse(event.data)
            // if(res.data.text === 'alive') {   // 与后端约定,心跳反馈标识为: alive,得到 alive 标识链接正常,什么也不做(待定)
            //     console.log("websocket接收信息")
            //     console.log(res);
            //     onMessageCallback(res)
            //     return
            // }
            console.log("websocket接收信息")
            console.log(res);
            onMessageCallback(res)
        } catch (error) {
            onMessageCallback(null)
        }
    }
}
/**
 * 连接成功后的回调函数
 */
function onOpen() {
    // 开启心跳
    start(this)
    console.log("websocket连接成功")
}

/**
 * 连接关闭后的回调函数
 */
function onclose(event) {
    if(event.code !== 1000) { // 不是手动关闭的话,进行重连
        console.log("wensocket非人为关闭关闭");
        reconnect(this)
    }else {
        // 主动关闭,不再重连
        console.log(this);
        clearTime(this)
        console.log(wsMap);
        // 删除 wsMap 中的数据
        wsMap.delete(this.wsKey)
        console.log(wsMap);
        console.log("wensocket连接关闭");
    }
}
/**
 * 报错时的回调函数
 */
function onError() {
    console.log("websocket建立连接失败");
}

/**
 * 初始化 websocket 
 */
function initWebSocket(
    url, 
    onMessageCallback,
    wsKey // 对应 socket 唯一的 key,为了指定唯一的访问地址
    ) {
    const wsurl = url.includes("ws://") ? url : "ws://" + getWebIP() + url
    socket = new WebSocket(wsurl)
    socket.onmessage = (event) => {
        onMessage(event, onMessageCallback)
    }
    socket.onopen = onOpen
    socket.onerror = onError
    socket.onclose = onclose
    // 初始化 props ,记录构建 socket 所提供的的信息
    initProps(socket, onMessageCallback, wsKey)
}

/**
 * 关闭 websocket 连接的方法
 */
function wesocketClose() {
    socket.close()
}


export {
    initWebSocket,
    wesocketClose
}
websocket的使用

在这里插入图片描述

vue.config.js中的代理配置

在这里插入图片描述

更多推荐