Nodejs + Socket.io + Nginx 搭建聊天

Nodejs + Socket.io + Nginx 搭建聊天

一、技术栈

  • 服务端
    • Nodejs (express框架)
    • Mongodb
    • Nginx
  • 前端
    • vue-element-admin(基于vue element-ui 的一套前端VUE框架)
  • Socket
    • Socket.io
  • 浏览器端消息通知
    • Notify.js

二、开发事项

1、前端代码

// index.vue






// 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使用wswss 的统一资源标志符,类似于 HTTPHTTPS ,其中 wss 表示在 TLS 之上的 Websocket ,相当于 HTTPS
2、socket 必须 使用broadcast 进行广播,才能将消息发送出去

五、未完善的工作

  • 1、目前的消息没有进行服务端存储
  • 2、登录后获取用户列表时应该把所有未读消息一并查出来

六、BUG

接收消息时会弹出两遍,一直没查出为啥,一脸懵逼中。。。希望有大神看到 帮忙排查一下

你可能感兴趣的:(Nodejs + Socket.io + Nginx 搭建聊天)