express路由中使用socket.io重复执行的问题
发布于 1个月前 作者 tashuo 312 次浏览 来自 问答

把socket监听事件放在 app.js 文件中,emit() 和 on() 事件都能正常执行,但是如果把socket监听放到express的一个控制器里面,代码就会出现重复执行,重复的次数跟websocket连接个数相等,关键代码如下:

    ...app.js关键代码
    var io = require('socket.io')(server);
    io.on('connection', function(socket){
        socket.emit('hi', 'hehehe');
        socket.on('hehe', function(data){
            console.log(data);
        });
        console.log(new Date()+' test');
    })

这样的代码可以正常执行,但是如果将上面的代码放到express的控制器里面就会出现问题:

    ...app.js关键代码
    var io = require('socket.io')(server);
    app.use('/users', users.test(io));
    
    ...users.js关键代码
    exports.test = function(io){
        return function(req, res){
        res.render('user', {'title': 'test'});
        io.on('connection', function(socket){
            socket.emit('hi', 'hehehe');
            socket.on('hehe', function(data){
                console.log(data);
            });
            console.log(new Date()+' test');
        });
    }

这样之后访问 localhost:3000/users 服务器下的输出内容跟websocket连接数相关,比如打开一个页面,console.log(data)这行会输出一次,刷新一次页面,则这行会输出两次,新建一个标签页打开这个页面的效果跟刷新一样,就好像在控制器下的socket监听的是所有的连接,为什么会出现这种情况? 如果socket要跟session交互,这个时候该怎么处理?

17 回复

connection event 就像是敲门,你整一个人去开门就好了。 第二段代码是每访问一次/users,你就派个人去门口,这样一开门,好几个人去问候,没必要嘛。

和session的交互,就交给在门口的那一个人处理好了

我一般把socket服务独立运行,看你的代码 不觉得怪怪的吗 自豪地采用 CNodeJS ionic

楼主是想把它挂载到某个url上吧。这样做是错的。

@leapon 嗯嗯谢谢 我刚接触node还有点不理解,每次刷新socket连接不是会断掉重连吗,为什么在 /users 下面刷新一次会增加一个socket连接?是跟 app.use('/users', users.test(io)); 这句话有关吗?它hold住这个socket连接了吗?

@hoozi 嗯嗯谢谢 初入node还有很多不明白的地方,如果将socket作为一个独立的服务运行,这个socket服务器要监听创建的http服务器还是单独一个端口?对socket连接进行验证的时候是通过解密cookie吗

@klesh 哦,也就是socket不能跟express的控制器相匹配工作?

@tashuo 监听同一个server,socketid和sessionid 貌似不是同一个东西

@hoozi 我也是在学习当中,如果要绑定登录用户的话,我用了一个变量user={}来存储每一个socket,跟数据库中的用户对应起来,但是这种做法不是持久化的。

@hoozi 嗯谢谢 我试一下这种方法

@tashuo 可以,只是你的理解方式不对,http server 和 socket server 是分开的两层。

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(socket){
    console.log("url"+socket.handshake.url);
    clientId=socket.handshake.query.clientId;
    console.log("connected clientId:"+clientId);
});
server.listen(3000);

上面的意思将 socket.io 附加到 http server 上,当 http server 接收到 upgrade websocket 时就将请求转给 socket.io 处理。如果你要根据 url 进行动作,在 on connection 进行处理。

@klesh 嗯谢谢 我现在在connection事件里面处理各个socket事件请求,只在socket连接建立前进行登录验证 authorization,并没有用到 socket.handshake.url ,这样做会有逻辑问题或安全问题吗,因为不同的socket事件存在于不同的url中?

你这样的话,每次刷新都会绑定一个新的监听对象

@tashuo 你的意思是要有 authorization 的请求才允许连接吗? 虽然我没实操经验,但是 express 是使用 connect 作为中间件管理的。 当有新的 http request 进来,connect 依次执行中间件,中间件们可以对信息进行加工,或者中断执行之类。。。 authorization 和 socket.io 应该都是以中间件形式插入到 connect 里面。 那么只要 authorization 发生在 socket.io 之前就能对未授权的 request 进行截停。 也就是说这两个中间件各自处理自己感兴趣的事情,你只要整理好前后顺序就行了。

@klesh 嗯嗯了解了,谢谢

回到顶部