首先说明一下什么是socket.io
,它和websocket
、Ajax
的区别在哪里。这里就不讲理论和运行机制了(我怕误人子弟…),只说一下我的理解。(socket.io/socketIO/socket
有时候称呼的很乱,我不太清楚有没有具体的区别和特殊的含义,我习惯叫socket.io
)
socket.io
和websocket
:websocket
是一种客户端和服务器之间双向实时通信技术,是HTML5
的新协议规范。websocket
在建立握手连接时,数据是通过HTTP协议传输的,但是在TCP
连接建立后,真正的数据传输阶段则不需要HTTP协议的参与。它讲究是随时随地的双向通信,应用场景包括客户端需要展示动态数据等。socket.io
则是为了兼容不同的浏览器,在websocket
上面封装了一层。socket.io
和Ajax
:Ajax
是单向的,即客户端通过HTTP协议和服务器单向通信,流程就是客户端发出请求,服务器做出相应。 socket.io
是双向的随时随地的通信,只是用一次HTTP协议建立连接TCP
连接后,就不在使用HTTP协议了。优点也很明显节省带宽(HTTP数据包头本身的字节量较大)和服务器资源。其他的详细介绍网上有很多就不在说了,网上说的千奇百怪的我就不贴网址了。下面说一下socket.io
在egg
+vue
项目中的具体使用。
egg
服务器端中使用:egg-socket.io的官方文档 个人觉得他说的已经很清楚了…我大概重述总结一下吧。1、安装开启插件。2、配置ws
引擎和命名空间。3、以sticky模式启动。4、配置Nginx
。5、写soceket.io
的controller和相应的router文件。(它中间件项目还没用到,我就不提了,有兴趣可以去看文档)。这个过程中需要动五个文件外加nginx
的配置文件。
0、安装:$ npm i egg-socket.io --save
1、plugin.js
文件:开启egg-socket.io
。
exports.io = {
enable: true,
package: 'egg-socket.io',
};
2、config.default.js
文件:配置ws
引擎和命名空间。
exports.io = {
namespace: {
init: { wsEngine: 'uws' }, //默认是ws引擎
'/': {
connectionMiddleware: [],
packetMiddleware: [],
},
},
};
3、package.json
文件:修改启动方式
{
"scripts": {
"dev": "egg-bin dev --sticky",
"start": "egg-scripts start --sticky"
}
}
4、nginx
的配置按照文档配置就行了,就不写了。
5、router.js
文件:配置路由。
module.exports = app => {
const { router, controller } = app;
app.io.of('/').route('request', app.io.controller.socketio.index); // namespace'/'要和配置的一致,消息名称'request'要和vue中一致
}
6、io/controller/socketio.js
文件:具体的业务代码
class SocketIOController extends Controller {
async index() {
const { ctx } = this;
const message = ctx.args[0]; //接受第一个参数:消息参数判断执行哪个函数
if (message === 'hello') {
const { param } = ctx.args[1] // 接受第二个参数:真正需要的参数
// ...中间是具体的业务代码
ctx.socket.emit('sendData', 'this is a response'); //消息名称'sendData'要和vue中一致,返回给客户端
}
}
}
module.exports = SocketIOController;
vue
客户端中使用:0、安装:npm install vue-socket.io --save
1、main.js
文件:引入vue-socket.io
// 引入 socketio,配置了环境变量NODE_ENV,区分开发环境用的,没用到的可忽略。
// 环境变量VUE_APP_DEV_SERVER是需要连接的服务器地址
import Vue from 'vue';
import VueSocketIO from 'vue-socket.io';
if (process.env.NODE_ENV === 'production') {
Vue.use(VueSocketIO, window.location.origin);
} else {
Vue.use(VueSocketIO, process.env.VUE_APP_DEV_SERVER);
// 等同于 Vue.use(VueSocketIO, socketio('http://xxx.xxx.xx.xxx'));
}
2、组件内使用
mounted() {
this.$options.sockets.sendData= (data) => { // ’sendData‘是由上面egg中controller中的emit决定的
console.log(data) // 接受到的消息输出为'this is a response'
};
this.$socket.emit('request', 'hello', { param: 'this is a param' }); // 'request' 是由egg的router决定的,后面是传给egg.controller的具体参数
if (!this.intervalData) { // 每五秒emit一次
this.intervalData = setInterval(() => {
this.$socket.emit('request', 'hello', { param: 'this is a param' });
}, 5000);
}
},
beforeDestroy() {
delete this.$options.sockets.sendData;
if (this.intervalTime) {
clearInterval(this.intervalTime);
this.intervalTime = null;
}
},
这样说明一下可能还是不太清楚(我也是尽力表达了),可以对比下图理解:
另外补充一点:nginx
的配置,及时配置好了本地开发时也会有cros
问题,但代码部署到服务器上的时候却没有cros
问题。是因为开发时本地页面访问云服务器,chrome 浏览器作了限制。我们项目的nginx
配置中已经add_header了,但是socket.io
的 response 本身也有个 Access-Control-Allow-Origin 头,add_header 后变成两个,所以就出现问题了。解决办法:修改 chrome 启动参数,在桌面上另建一个快捷方式,目标加--disable-web-security --user-data-dir="C:\temp"
参数,开发时使用这个快捷方式启动浏览器。