socket 网址:英文官网
一、 WebSocket 简介
前端和后端的交互模式最常见的就是:前端发数据请求,从后端拿到数据后展示到页面中。
如果前端不做操作,后端不能主动向前端推送数据,这也是http协议的缺陷。
一种新的通信协议应运而生 WebSocket,它最大的特点就是服务端可以主动向客户端推送消息,客户端也可以主动向服务端发送消息,实现了真正的平等。
WebSocket 其他特点:
- 建立在 TCP 协议之上,服务器端的实现比较容易;
- 与 HTTP 协议有着良好的兼容性;
- 默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效;
- 可以发送文本,也可以发送二进制数据;
- 没有同源限制,客户端可以与任意服务器通信;
- 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL;
二、vue中使用websocket
- 安装及引入
vue-socket.io 其实是在 socket.io-client(在浏览器和服务器之间实现实时、双向和基于事件的通信) 基础上做了一层封装,将 $socket 挂载到 vue 实例上,同时可使用 sockets 对象轻松实现组件化的事件监听,在 vue 项目中使用起来更方便。
安装:
npm i vue-socket.io
引入:
// main.js
import Vue from 'vue'
import store from './store'
import App from './App.vue'
import VueSocketIO from 'vue-socket.io'
Vue.use(
new VueSocketIO({
// 生产环境建议关闭,开发环境打开(在控制台看到socket连接和事件监听的信息)
debug: true,
connection:'http://metinseylan.com:1992',
options:{
// 创建时是否自动连接 我们这里设定为false,在指定页面再开启
autoConnect: false,
// 路径(默认值:/socket.io/)
path: "/my-app/",
// 目前有两种传输方式:HTTP long-polling(可简称:polling)、WebSocket
transports: ['polling'],
// 附加请求头(在服务器端的 socket.handshake.headers 对象中找到)
extraHeaders:{},
},
// 如果没有使用到 store 可不写
vuex: {
store,
actionPrefix: 'SOCKET_',// vuex action 前缀
mutationPrefix: 'SOCKET_', // vuex mutation 前缀
},
})
)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
组件内使用:
<template>
<div class="wrap">
<button @click="socketEmit">连接Socket</button>
<button @click="socketSendmsg">发送数据</button>
</div>
</template>
<script>
export default {
data(){
return {
randomId:null,
}
},
methods:{
socketEmit(){
// 开始连接 socket
this.$socket.open();
// 订阅事件,testCall 是与后端约定好的名称
this.sockets.subscribe('testCall', (res) => {
if(res.code == 200 && res.randomId === this.randomId){
console.log('召唤成功')
}
})
},
// 发送消息
socketSendmsg(){
this.randomId = Math.random();
// testCall 是与后端约定好的名称
this.$socket.emit('testCall', {
"randomId": this.randomId,
"deviceId": "123456"
});
},
},
sockets: {
connect: function () {
console.log('连接成功')
},
disconnect: function () {
console.log('断开连接')
},
reconnect: function () {
console.log('重新连接')
},
},
beforeDestroy(){
// 关闭 Socket
this.sockets.unsubscribe('testCall');
this.$socket.close();
},
}
</script>
三、vue真实项目使用(vue+ts)
1)安装:npm i vue-socket.io
2)新建socket.ts文件,与app.vue文件同级;
/**
* ! socket在全部环境下使用,但仅在开发环境会在控制台抛出错误日志信息
* 这个项目因为有用户权限管理,所以给后台发送token验证通过后,才后走通socket。如果项目不需要,直接在
*/
import store from './store'
import VueSocketIO from 'vue-socket.io' // vue-socketio
import SocketIO from 'socket.io-client' // socketio
import Cookies from 'js-cookie'
// 正常项目,这里要再加一个token的参数;因为当前项目有权限管理,需要发送token给后端验证通过,所以token做了发送事件:socketInstance.emit('register', Cookies.get('yi-token'))
})
const socketInstance = SocketIO(process.env.VUE_APP_BASE_WS as string, {
reconnectionAttempts: 5,
timeout: 5000
})
// 开发环境做了打印配置;
if (process.env.NODE_ENV === 'development') {
socketInstance.on('connect_error', () => {
console.log('%cSocket:', 'color:#EA3D2F;font-weight:500', 'Websocket init failed')
})
socketInstance.on('connect', () => {
console.log('%cSocket:', 'color:#00B69B;font-weight:500', 'Websocket init succeed')
// 发送事件,入参token
socketInstance.emit('register', Cookies.get('yi-token'))
})
} else {
// 线上
// 此处发送了事件token给后端,后端验证用户信息;此项目的特殊处理
socketInstance.on('connect', () => {
socketInstance.emit('register', Cookies.get('yi-token'))
})
}
// 实例化一个VueSocketIO
const VueSocketIOInstance = new VueSocketIO({
debug: process.env.NODE_ENV === 'development',
connection: socketInstance,
vuex: {
store,
actionPrefix: 'SOCKET_',
mutationPrefix: 'SOCKET_'
}
})
export default VueSocketIOInstance
vuex做了如下配置store/task,js
export default {
namespaced: true,
state: {
noticeCount: 0,
licenseUpdate: 0
// taskProcess:{},
},
mutations: {
// 需要使用 SOCKET_, vuex mutation 前缀
// 消息提示(数字)
SOCKET_notice_count(state, data) {
state.noticeCount = data
},
// 漏洞库管理已过期
SOCKET_license_update(state, data) {
state.licenseUpdate = data
}
},
actions: {},
}
封装了一个socket.vue文件,放在sidebar中,登录页面进来直接调用;
socket.vue文件
<template>
<div />
</template>
<script lang="ts">
import Vue from 'vue'
/**
* websocket 组件,写 tmplate 仅仅为了让 vue 不报错
*/
export default Vue.extend({
name: 'SocketComponent',
sockets: {
// 获取socket推送消息提示
notice_count() {
// console.log('socket组件中 noticce_count', data)
}
}
})
</script>
sidebar.vue文件:
<template>
// 使用socket
<Socket />
</template>
以上配置完成后,页面中开始使用:
业务逻辑页面: popbox.vue, 监听$store.state.task.noticeCount.count’即可,有数据直接显示;
watch: {
'$store.state.task.noticeCount.count': {
handler: function (val) {
if (val > 0) {
localStorage.removeItem('NOTICE_COUNT_FROMLOGIN')
this.total = val
}
},
deep: true
},
业务逻辑页面:system.vue: 监听前后数据是够一致,不一致调用接口更新提示语;
watch: {
'$store.state.task.licenseUpdate.count': {
handler: function (newval, oldval) {
if (oldval !== newval) {
this.freshLicenseInfoEvent(true)
}
},
deep: true
}
}
业务逻辑页面,根据具体需求,具体来实现。
参考:https://blog.csdn.net/ZYS10000/article/details/122737466
参考文章: https://blog.csdn.net/ZYS10000/article/details/113056868