一、补充知识点
websocket
websocket实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
而HTTP 协议通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息
npm i ws -S
后端:
1、创建web_socket_service.js文件
在 app.js 文件中:
// 引入WebSocket
const webSocketService = require('./service/web_socket_service')
webSocketService.listen() // 开启监听
在 web_socket_service.js 中:
const WebSocket = require('ws')
const path = require('path')
const {
getFileJsonData
} = require('../utils/file_utils')
// 1、创建WebSocket服务端对象,绑定端口
// const WebSocket = require('ws')
const ws = new WebSocket.Server({
port: 9998,
}, () => {
console.log('websocket is listening port: 9998');
})
module.exports.listen = () => {
// 2、对客户端连接事件进行监听,client是客户端的socket连接对象
ws.on('connection', (client) => {
console.log('client connected successfully, total client:' + ws.clients.size);
// 3、对客户端的连接对象进行message事件监听,msg由客户端发送给服务端的数据
client.on('message', async (msg) => {
const payload = JSON.parse(msg)
2、服务端接收数据字段约定
3、服务端发送数据字段约定
const action = payload.action
if (action === 'getData') {
// 取出图表名,然后获取数据,再添加data字段给前端
// payload.chartName取出数据中心的chartName字段
filePath = `../data/${
payload.chartName}.json`
// fullPath拼接json文件的路径
let fullPath = path.join(__dirname, filePath) // 保证动态的绝对路径
// 保证后台不崩溃,就需要用try-catch
try {
// getFileJsonData读取该文件的内容
let data = await getFileJsonData(fullPath)
// 需要在服务端获取到数据的基础之上,增加一个data的字段
// data所对应的值,就是某个json文件的内容
payload.data = data
client.send(JSON.stringify(payload))
} catch (error) {
payload.data = null
client.send(JSON.stringify(payload))
}
} else {
// 不是获取数据,直接原封不动地发给每个客户端
// clients所有客户端的连接,效果就是假如说1号全屏开启,那么2号和3号就会自动全屏显示效果
ws.clients.forEach(item => {
item.send(msg)
})
}
})
})
}
前端:
1、创建socketUtils.js文件
在main.js中:
import SocketService from '@/utils/socketUtils'
SocketService.Instance.connect() // 创建实例并连接服务器
// 挂载到Vue原型身上,方便用this.$socket
Vue.prototype.$socket = SocketService.Instance
在socketUtils.js文件中:
export default class SocketService {
// 单例设计模式
static instance = null
// 在Instance方法中先判断this.instance是否存在
static get Instance() {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
ws = null
callBackMapping = {
} // 存储回调函数
hasConnected = false // 标识是否连接成功
sendRetryTimes = 0 //记录失败次数
connectRetryTimes = 0
// connect定义连接服务器的方法
connect() {
// 判断浏览器是否支持WebSocket
if (!window.WebSocket) {
return window.alert('您的浏览器不支持WebSocket。')
}
this.ws = new window.WebSocket('ws://localhost:9998')
this.ws.onopen = () => {
// 监听一些事件
console.log('connected server successfully');
this.hasConnected = true
this.connectRetryTimes = 0
}
this.ws.onclose = () => {
console.log('connected server failed');
this.hasConnected = false
this.connectRetryTimes++
window.setTimeout(() => {
this.connect()
}, 500 * this.connectRetryTimes)
}
//得到服务端发送过来的数据
this.ws.onmessage = (msg) => {
// 监听服务端发送消息
const data = JSON.parse(msg.data)
const socketType = data.socketType //得到回调函数的标识
// 判断回调函数是否存在
if (this.callBackMapping[socketType]) {
const action = data.action
if (action === 'getData') {
const chartData = JSON.parse(data.data)
// console.log('前端收到数据:', data.data);
this.callBackMapping[socketType].call(this, chartData)
} else if (action === 'fullScreen') {
this.callBackMapping[socketType].call(this, data)
} else if (action === 'themeChange') {
this.callBackMapping[socketType].call(this, data)
}
}
}
}
// 因为下面几个方法是在vue组件里调用的,因此挂载到vue原型上比较方便
registerCallBack(socketType, callback) {
// 回调函数注册,以socketType为key
this.callBackMapping[socketType] = callback
}
unregisterCallBack(socketType) {
// 注销回调函数
this.callBackMapping[socketType] = null
}
// 发送数据的方法
send(