如何在客户端使用 vue-socket.io 与服务器端实时双向通信
前言
基本的 HTTP 请求可以满足客户端访问数据的需要。如果需要“实时”刷新数据,可以采用轮询(设置一个定时器,每隔很短的一段时间发送 HTTP 请求重新获取数据)或长轮询(long poll,服务端收到 HTTP 请求后,将回调阻塞到有新数据产生)的方式。
轮询需要持续频繁地发送请求,会造成带宽和服务器资源的浪费。
长轮询需要服务器保持长连接,会增加服务器的开销。
相比于以上两种方式,WebSocket 真正实现了实时通讯。
轮询方式的背景是 HTTP 请求的被动性,也即客户端发起一次 Request,有且仅有一次 Response,服务端被动接收客户端的请求来进行操作。说白了,就是服务端没办法主动去跟客户端“说话”。
WebSocket 协议建立在 HTTP 协议的基础上,通过一次 HTTP 请求与服务器建立连接,以订阅-发布的模式让服务端可以主动联系客户端。
订阅-发布模式:客户端使用 主题(topic) 向服务端订阅消息,服务端在相关主题有新消息时,向所有订阅了该主题的客户端发布消息
vue-socket.io 在 vue 中的使用
使用前,强烈建议大家阅读官方文档与源码,也可以看一下知乎的使用介绍。
安装依赖
npm install vue-socket.io --save
注:--save
安装的依赖将放在 package.json 中的 dependencies
下。与之对应的 --save-dev
将放在 devDependencies
这个情况下依赖不会打包到 dist 里。WebScoket 是项目运行时必须的依赖,所以只能使用 --save 进行安装。
在 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({
debug: true,
connection: 'http://metinseylan.com:1992',
vuex: {
store,
actionPrefix: 'SOCKET_',
mutationPrefix: 'SOCKET_'
},
options: { path: "/my-app/" } //Optional options
}))
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在 main.js 引入模块将自动注册相关对象,可以在任意位置使用:
// 发送信息给服务端
this.$socket.emit('login',{
username: 'username',
password: 'password'
});
// 接收服务端的信息
this.sockets.subscribe('relogin', (data) => {
console.log(data)
})
在模板 .vue 局部引入模块(特殊情况下使用)
在 script 标签内部,创建 socket 全局变量(VueSocketIO 的对象)。
import VueSocketIO from 'vue-socket.io';
var socket = new VueSocketIO({
debug: true,
connection: SocketIO(Setting.apiBaseURL),
vuex(){}
});
在控制台打出 socket 对象,可以看到其内部封装了 io,Emitter,Listener 三个关键对象。稍微看一下,就会发现,io 对象和之前的 this.$socket 是同一个对象,因此可以使用:
// 发送信息给服务端
this.socket.io.emit('login',{
username: 'username',
password: 'password'
});
这个时候一个大大的问号就到了笔者的脑子里了,这个 this.sockets 是个什么玩意儿???
查了很多博客,这个 sockets 依旧葆有其神秘的面纱,没办法了,看源码去:
/**
* Assign runtime callbacks
*/
beforeCreate(){
if(!this.sockets) this.sockets = {};
this.sockets.subscribe = (event, callback) => {
this.$vueSocketIo.emitter.addListener(event, callback, this);
};
this.sockets.unsubscribe = (event) => {
this.$vueSocketIo.emitter.removeListener(event, this);
};
},
在 Vue-Socket.io/src/mixin.js
文件里可以找到对 sockets 对象的定义。
很明显,之前的 this.sockets.subscribe
不过是对 Emitter 的小小封装,那么我们就可以使用:
// 接收服务端的信息
socket.emitter.addListener('relogin', (data) => {
console.log(data)
})
结语
因为项目特殊需要,所以需要在模板中局部引入和使用 vue-socket.io,这个着实难倒了笔者。但也印证了看源码的重要性,查了大量的资料,试了各种奇奇怪怪的可能,不如看下源码,才知道自己被安排的明明白白的。
参考
个人总结,敬请指正。