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即可完成在实际项目中的应用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 英文文档,一开始我也是抗拒的,边翻译边看,也就花费了1个小时基本就阅读过了,我的英文基础其实很差。附上链接:链接:...
    lonecolonel阅读 9,850评论 3 1
  • 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-WebSo...
    敢梦敢当阅读 8,882评论 0 50
  • 一些参考内容: https://www.ntu.edu.sg/home/ehchua/programming/we...
    貘鸣阅读 2,088评论 0 1
  • 【感恩日记 2019-2-20 雨】 1.感恩有能量的自己,利索起床准备早饭,煮鸡蛋,牛奶,热馒头和汤圆,满意。 ...
    心理咨询师萍阅读 183评论 0 4
  • 今天看了芒果新节目,向往的生活;真心觉得这样的生活很令人向往了,密云雾灵山下的小村庄,到处是绿油油的植物农作物,大...
    sunpanda阅读 712评论 0 2