【问题标题】:Why does Socket.io server override node http middleware?为什么 Socket.io 服务器会覆盖节点 http 中间件?
【发布时间】:2018-06-08 09:29:56
【问题描述】:

在初始 HTTP 升级后,我制作了一个完全依赖 WebSockets 的 React 应用程序。出于安全原因,我在 WebSockets 连接中使用 cookie 和 JWT 令牌。

一切正常,但是当打开一个新标签时,socket.io cookie 会重新发布,我希望用户通过多个标签保持登录状态。因此,如果客户端还没有 cookie,我想设置一个 cookie。如果它已经有一个,那么就使用那个 cookie。

所以我想在 Node 的 http 服务器中处理第一个 HTTP 轮询请求并为此创建中间件:

// HTTP SERVER
const server = require('http').createServer(function (request, response) {
  console.log('test');
  console.log(request);

  if(!request.headers.cookie) { // cookie pseudo-logic
    response.writeHead(200, {
    'Set-Cookie': 'mycookie=test',
    'Content-Type': 'text/plain'
  });
}

// Socket.IO server instance
const io = require('socket.io')(server, {
  origins: config.allowedOrigins,
  cookie: false, // disable default io cookie
});

server.listen(port, () => console.log(`Listening on port ${port}`));

我使用 Socket.io 作为 WebSockets 框架。然而问题是,在注册 Socket.io 服务器时,这个中间件会被忽略。当我注释掉 Socket.io 服务器时,中间件处于活动状态并记录了请求。

看起来 Socket.io 的服务器正在覆盖节点 http 的服务器的处理程序。然而,在 Socket.io 文档中,他们提供了这个示例:

var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');

app.listen(80);

function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

因此表明应该可以处理第一个 http 轮询请求以及套接字请求。我设法让它与 Express 一起工作,但我不明白为什么 node 的 http 服务器不能。

有谁知道发生了什么?

提前致谢,

迈克

【问题讨论】:

  • 改用socket.io middleware。这将允许您参与初始 socket.io 连接。这就是它的用途。
  • 我知道,但我想实现决定是否需要设置 cookie 的逻辑。如果客户端已经发送了 cookie,则不会设置新的 cookie。如果没有,则设置一个新的 cookie。无法从 socket.io 设置 cookie。所以我想在建立 WebSocket 连接之前处理请求。但是我设法用 Express 中间件做到了,但我不明白为什么它不适用于 Node 的 http 服务器。

标签: node.js socket.io


【解决方案1】:

因为 socket.io 的正常使用不希望常规 http 中间件看到 socket.io 连接请求(它们通常会触发 404 响应),所以 socket.io 将自己的请求处理程序放在任何其他请求处理程序之前,即使是那些在安装之前就存在了。

你可以在这里看到它是如何做到的:https://github.com/socketio/engine.io/blob/master/lib/server.js#L437 在 engine.io 源代码中。

我可以想到以下方法让你在 socket.io 看到请求之前对其进行预处理:

  1. 在 socket.io 看到请求之前,使用代理并在代理中处理 cookie。
  2. 修补 socket.io/engine.io 代码以添加回调挂钩以执行您想要执行的操作。
  3. 复制 socket.io/engine.io 使用的技术,在 socket.io 配置后将您自己的请求处理程序放在首位。
  4. 找到一种方法来覆盖 socket.io 服务器对象的 handleRequest() 方法,当有传入的连接请求时调用该方法。你可以看到它的代码here

【讨论】:

  • @Maikkeyy - 这能回答你的问题吗?
  • 是的,谢谢。我忘了回应。为我自己澄清一下:使用代理到底是什么意思?首先让用户访问网络服务器上的另一个端口(代理)并在那里处理身份验证,然后在成功身份验证后打开 WebSockets 连接?因为这也可以在同一个域上完成,对,就像我在示例中尝试的那样。然后首先通过 HTTP 处理身份验证,然后打开 WebSockets 通道。它与 express 一起工作,是否意味着 socket.io 不会覆盖来自 Express 的请求处理程序?
  • @Maikkeyy - 我的意思是,位于您服务器前面的代理可以在您的服务器看到传入连接之前透明地对传入连接执行任何操作,然后,如果合适,让它通过您的服务器(修改或未修改)。这是解决此类问题的一种架构。在这种情况下,它可能不是我的首选,因为您可能可以使用其他选项之一来解决您的问题。我可能会从调查选项 4 开始。
  • 啊,好吧,我明白了。谢谢!选项 2 的缺点可能是可维护性,对吧?因为当您将 socket.io 更新为依赖项时,它可能会覆盖您的回调挂钩?然后,回调挂钩将例如重新添加节点 http 的请求侦听器,因为它们会删除您提供的源中的所有请求侦听器?
  • @Maikkeyy - 是的,出于可维护性的原因,选项 2 可能是我的最后选择。使用其他选项之一要好得多。我个人会先看选项 4,然后再看选项 3,因为两者都可以在现有服务器上完成,而无需修改 socket.io 代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 2014-01-17
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
  • 2014-11-04
  • 1970-01-01
相关资源
最近更新 更多