webSocket配合koa2使用-非demo环境下模块化使用webSocket

本文记录一次koa2环境下使用原生node ws模块的过程
  1. 首先需要引入ws模块(本人使用的是koa-generator初始化的项目,对应createserver操作在/bin/www.js文件中),ws模块是nodejs原生模块,不太依赖任何库,文档地址:https://www.npmjs.com/package/ws

    const WebSocket = require('ws')
    
  2. 创建一个wss服务器,挂载到现有server服务器上,目的是和原有server使用同一端口,同源带来的好处很多,会为你减少很多麻烦

    var server = http.createServer(app.callback());//koa脚手架创建的服务器
    
    let wss = new WebSocket.Server({
        server: server//挂载到原有服务器上,不然你得重新开一个端口,详见文档
    })
    
  3. 写一个ws模块并引入

    
    //外部
    var server = http.createServer(app.callback());
    let wss = new WebSocket.Server({
        server: server
    })
    WSOrder.createWss(wss)//使用createWss方法开始开启监听
    
    
    //内部
    module.exports = {
        createWss: function (wss) {
            wss.on('connection', function (ws) {
                this.numClients++
                ws.isAlive = true;
                ws.on('pong', this.heartbeat);//测速激活连接
                this.handle(wss)//连接第一次广播
                ws.on('close', function () {//监听连接优雅断开
                    this.numClients--
                }.bind(this))
            }.bind(this))
            this.wss = wss//讲第一次创建连接时导入的传入的wss保存起来,以便在其他路由中使用时可以直接传入,因为handle函数必须传入wss,而普通路由中没有这个wss,只又www.js文件中有
    
        },
        numClients: 0,//连接计数器
        async handle (wss) {
            let data = {}
            //在此处可以写业务逻辑,如查询数据库设置返回内容
            console.log('webSocket connectClients: ' + this.numClients)
            wss.clients.forEach(function each(client) {
                if (client.isAlive === false) {//如果非优雅断开 则强制停止 如网线被拔掉
                    this.numClients--
                    return client.terminate()
                }
                client.isAlive = false;//先设置成false
                client.ping(this.noop)//尝试ping如果响应则true
                client.send(JSON.stringify(data));//发送消息
            })
        },
        //当然 你也可以写其他很多不同handle,方便在不同场景使用
        heartbeat () {
            this.isAlive = true
        },
        noop() {
        }
    }
    
  4. 在其他文件中使用时如在route页面中需要广播

    //其他文件中
    const WSOrder = require('../wss/order')
    //导入后便可使用handle方法进行广播
    WSOrder.handle (WSOrder.wss) //需要传入一直之前保存的wss对象
    
  5. 如果你需要创建多个wss服务,如开启两个不相干的聊天室,可以是这样设置

    const wss1 = new WebSocket.Server({ noServer: true });
    const wss2 = new WebSocket.Server({ noServer: true });
     
    WSOrder1.createWss(wss1)
    
    WSOrder2.createWss(wss2)
    //你可以创建两个WSOrder  当然 你可以共用一个WSOrder前提是在封装的时候
    module.exports = function (){
     return {}
    }
    WSOrder().createWss(wss1)
    WSOrder().createWss(wss2)
    //如果你共用一个WSOrder需要将wss对象保存起来,因为你在route内require也将会是一个新的对象 而不是原来的wss
     
    server.on('upgrade', function upgrade(request, socket, head) {
      const pathname = url.parse(request.url).pathname;
     
      if (pathname === '/foo') {
        wss1.handleUpgrade(request, socket, head, function done(ws) {
          wss1.emit('connection', ws, request);
        });
      } else if (pathname === '/bar') {
        wss2.handleUpgrade(request, socket, head, function done(ws) {
          wss2.emit('connection', ws, request);
        });
      } else {
        socket.destroy();
      }
    });
    
  6. 在客户端可以这样操作

    window.ws = new WebSocket(`wss://***.***.***/order`)
          ws.onopen = () => {
            console.log('WebSocket onopen')
          }
          ws.onmessage = e => {
            //接收消息并处理
          }
    
  7. 注意:wss服务是独立于koa执行的一个服务,虽然他们共用一个端口,但是并不会经过koa中间件,所以的koa中间件控制登陆状态将失效,也就是说客户端有可能绕过你的登陆检测就可连接wss,所以你有必要使用cookies判断当前用户(在ws.upgradeReq中找)

  8. 如果项目中使用了nginx的proxy反向代理,需要单独设置ws连接,因为这是一个101状态的http请求,主要在代理是设置header

    location /order {
            proxy_pass         http://localhost:3001;
            proxy_http_version 1.1;
            proxy_read_timeout 1800s; //设置连接有效事件为30min(自行设置)如不设置连接1分钟,如不发心跳包即断开,这里直接设置连接时间方便
            proxy_set_header   Upgrade $http_upgrade; 
            proxy_set_header   Connection "upgrade";
        }
    
  9. 经过以上设置即可完成ws在koa2项目上的基本所有配置,再调用一些如.send onmessage等api即可完成在实际项目中的应用

你可能感兴趣的:(webSocket配合koa2使用-非demo环境下模块化使用webSocket)