Nodejs + Socket.io + Nginx 搭建聊天
一、技术栈
- 服务端
- Nodejs (express框架)
- Mongodb
- Nginx
- 前端
- vue-element-admin(基于vue element-ui 的一套前端VUE框架)
- Socket
- Socket.io
- 浏览器端消息通知
- Notify.js
二、开发事项
1、前端代码
// index.vue
-
{{msg.sendUserName}}
{{msg.content}}
按钮栏
// socket-io.js
import io from 'socket.io-client';
// 浏览器 消息提醒 组件
import Notify from '@wcjiang/notify';
// let a_interval;
let chatSocket;
const iNotify = new Notify({
effect: 'flash',
audio: {
// 可以使用数组传多种格式的声音文件
file: '/static/media/message_remind.mp3'
}
});
const BASE_API = {
development: 'http://localhost:8008',
production: `${location.origin}`
};
export default {
methods(ms) {
return ms;
},
/**
* 初始化SocketIO
* @param {String} loginUserId 当前登录的用户的ID
*/
init(loginUserId, methods) {
const that = this;
this.methods = methods;
// 与聊天服务器进行连接
chatSocket = io.connect(`${BASE_API[process.env.NODE_ENV || 'production']}/chat`);
// 接收到其他用户 从 服务器发来的信息
const socketType = `chat:server-sendMsg-to-user:${loginUserId}`;
chatSocket.on(socketType, this.receiveMsgFromUserThroughServer.bind(this));
chatSocket.on('hello-client', function(data) {
console.log(data);
});
chatSocket.on('server-response', (msg) => {
that.playNewMsg(iNotify, msg);
});
},
sendMsg(msg) {
chatSocket.emit('chat:user-sendMsg', msg);
},
/**
* 接收到其他用户发来的信息
* @param {Object} msg
*/
receiveMsgFromUserThroughServer(msg) {
// 回调 vue 中传过来的方法,用于操作 消息列表
this.methods.receiveMsgFromUserThroughServer(msg);
this.playNewMsg(iNotify, msg);
},
// 播放消息提醒
playNewMsg(iNotify, msg) {
iNotify.player();
iNotify.notify({
title: msg.sendUserName,
body: msg.content,
onclick: function() {
window.focus();
},
onshow: function() {
console.log('on show');
}
});
}
};
2、服务端代码
let server = null;
let io = null;
let _socket = null;
let chat = null;
const socketIO = {
/**
*
* @param {ExpressServer} app express()
*/
init(app) {
server = require('http').Server(app);
io = require('socket.io')(server);
server.listen(8008);
io.on('connection', this.onConnect.bind(this));
/**
* 创建 聊天专用 namespace
*/
chat = io.of('chat');
chat.on('connection', this.onChatConnect.bind(this))
},
/**
* 根链接
* @param {Socket} socket
*/
onConnect (socket) {
_socket = socket;
// 通知客户端,已与服务端建立链接
socket.emit('hello-client', { 'server-msg': '与服务器连接成功' });
// 客户端 向服务端打招呼
socket.on('hello-server', function (data) {
console.log(data);
socket.emit('server-response', `服务端接收到消息:${data.my}`);
});
},
/**
* 聊天 namespace
* @param {Socket} socket
*/
onChatConnect (socket) {
const that = this;
socket.emit('hello-client', { 'server-msg': '聊天链接--与服务器连接成功' });
// 接收到用户发来的消息
socket.on('chat:user-sendMsg', function (msg) {
that.receiveUserSendMsg(socket, msg);
});
},
/**
* 接收到用户发来的信息
* @param {Socket} socket
* @param {Object} msg
*/
receiveUserSendMsg (socket, msg) {
const socketType = `chat:server-sendMsg-to-user:${msg.receiveUserId}`;
console.log('将信息发送给目标用户:', socketType);
/**
* 必须通过 broadcast 进行广播,才能将消息发送出去
*/
socket.broadcast.emit(socketType, msg);
}
}
module.exports = socketIO;
三、部署事项
1、消息通知
由于消息通知基于 浏览器的 Notifications API,但是它基于Https
,所以项目需要部署为https
。
https
的域名申请自行解决。
2、Nginx部署
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /var/www/art_key/你的私钥.pem;
ssl_certificate_key /var/www/art_key/你的公钥.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 前端静态资源
location / {
root /var/www/example/dist;
index index.html;
}
# 后端接口的 location
location /api/ {
proxy_pass http://127.0.0.1:4040;
}
# socket 服务的 location
location /socket.io/ {
proxy_pass http://127.0.0.1:8008;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
四、其他
1、Websocket
使用ws
或 wss
的统一资源标志符,类似于 HTTP
或 HTTPS
,其中 wss
表示在 TLS
之上的 Websocket
,相当于 HTTPS
。
2、socket
必须 使用broadcast
进行广播,才能将消息发送出去
五、未完善的工作
- 1、目前的消息没有进行服务端存储
- 2、登录后获取用户列表时应该把所有未读消息一并查出来
六、BUG
接收消息时会弹出两遍,一直没查出为啥,一脸懵逼中。。。希望有大神看到 帮忙排查一下