【问题标题】:Wait for socketio event inside express route在快速路由中等待 socketio 事件
【发布时间】:2015-11-06 16:22:49
【问题描述】:

我在我的应用程序中使用 express、socketio 和 socketio-client。 (我对 nodejs 堆栈不太满意...)

总结一下我的申请流程: Client => node/express API + Socketoi server nodejs (Socketio-client)

  1. 浏览器向 nodejs/express(路由 /api)发送请求
  2. 使用中间件覆盖一些请求标头
  3. 在路由'/'中,服务器向nodejs(Socketio-client)发送一个emit
  4. 执行一些逻辑后,socketio-client 会发出一个带有逻辑结果的事件
  5. 我需要将此结果作为响应发送给客户端

我的代码如下:

router.get('/*', function (req, res) {
  //emit data for socketio-client to apply some logic
  app.io.sockets.emit('req', {
    reqheader : req.headers,
    requrl : req.protocol + "://" + req.headers.host + req.url,
    reqmethod : req.method
  });
  console.log("after emit");
  //I use callback to make response wait for socketio server to catch event from client
  waitforevent(req, res, function (__res) {
    console.log("callback" );
    res.end(__res.body);
    res.sendStatus(__res.statusCode);
    //res.end();
  });
  function waitforevent(req, res, callback) {
    console.log("waiting for event" );
    app.io.__socket.on('respp', function (data) {
        //console.log("no response yet \n" + JSON.parse(data) );
        __res = JSON.parse(data);
        console.log("event catched...");
        callback(__res);
    });
  }
});

我的问题: 这仅在我第一次从浏览器发送 Get http://localhost:3000/api 时有效。 __res.body 打印在浏览器中。

req 1
after emit
waiting for event
event catched...
callback
Error: Can't set headers after they are sent.   
**GET /api 200 73.841 ms - -**

req 2
after emit
waiting for event

下一个请求将等待服务器响应,我怀疑这不会发生,因为服务器永远不会捕获 app.io.__socket.on('respp', function (data){...} .

在发送更多请求后(其他人正在等待),我在服务器日志中注意到了这个警告:

(node) warning: possible EventEmitter memory leak detected. 11 respp listeners added. Use emitter.setMaxListeners() to increase limit.

在向客户端发送响应之前,还有其他方法可以捕获路由中的事件吗?

【问题讨论】:

  • 你能把完整的代码分享给我吗?以下答案不再起作用

标签: javascript node.js express socket.io


【解决方案1】:

我用once解决了:

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);

var socket;
io.on('connection', function (sock) {
    console.log('Connected');
    socket = sock;
});

server.listen(3000);

app.get('/*', function (req, res) {
    socket.once('event', function (data) {
        if (data.error) {
            console.log('is an error');
            res.status(400).json(data);
        } else {
            console.log('is ok');
            res.status(200).json(data);
        }
    });
    io.emit('ask-for-event', { data: data });
});

【讨论】:

  • 尽管基本上没有解释,但将“on”替换为“once”确实为我解决了这个问题。我不确定为什么会多次发出或捕获该事件,但似乎确实如此。至少对我来说。
【解决方案2】:

您可以在套接字关闭时移除事件侦听器以避免事件侦听器泄漏:

router.get('/*', function (req, res) {
  app.io.sockets.emit('req', {
    reqheader : req.headers,
    requrl : req.protocol + "://" + req.headers.host + req.url,
    reqmethod : req.method
  });

  req.socket.on('close', function() {
    app.io.__socket.removeListener('respp', resppHandler);
  });
  app.io.__socket.on('respp', resppHandler);

  function resppHandler(data) {
    data = JSON.parse(data);
    res.statusCode = data.statusCode;
    res.end(data.body);
  }
});

我不确定app.io.__socket 是否真的应该是app.io.sockets,但我从您的代码中照原样复制了它,假设您知道自己在做什么。

此外,您可能希望添加某种超时,以免请求无限期等待。

【讨论】:

猜你喜欢
  • 2018-07-09
  • 2018-09-09
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
  • 2018-07-15
  • 2013-03-08
  • 1970-01-01
  • 2013-09-22
相关资源
最近更新 更多