我对如何以及为什么设置 node.js 应用程序以及任何 app.use 函数如何工作一无所知 - 关于它的教程没有解释任何原因。
无论如何,我在 app.js 根文件中设置了 socket.io、res.locals 和 index.js。
const sockets = require('./models/socket')(io)
app.use(function (req, res, next) {
res.locals.user_id = req.session.user_id;
next();
});
const routes = require('./routes/index');
app.use('/', routes);
Run Code Online (Sandbox Code Playgroud)
我希望能够访问 socket.js 模型中的 res.locals,就像我可以在路由文件夹中的 index.js 中一样。
我无法猜测如何去做这件事。如果有人能够解释我如何以及为什么可以或不能,那将是一个奖励。谢谢!
欢迎使用 Expressjs,在进一步研究之前,您可能应该研究一些基础知识,它们将有助于解决您的一些困惑。我将对它们进行简要说明,但我建议您做进一步的研究。我会在最后回答你的实际问题。
中间件和 app.use
Expressjs 建立在一个想法之上,即一切都只是“中间件”。中间件是作为请求链的一部分运行的功能。请求链本质上是一个单一的客户端请求,然后通过一系列中间件函数,直到它到达链的末端,通过向客户端返回响应或错误而提前退出。
Express 中间件是一个函数,它接受以下三个参数。
next();错误next(new Error());。如果调用为空,则触发下一个中间件,如果调用有错误则调用第一个错误中间件。如果next没有在中间件的末尾调用,则认为请求已完成并将响应对象发送给用户。app.use 是一种设置中间件的方式,这意味着它将为每个请求运行(除非next()由于某种原因没有被前一个中间件调用,或者它被调用时出错)。该中间件将任何HTTP请求类型(运行GET,POST,PUT,DELETE,等等)。
app.use 可以带多个参数,初学者学习的重要参数是:app.use(func)和app.use(path, func)。前者设置“全局”中间件,无论客户端请求什么端点(url 路径),它都会运行,后者(具有特定路径)仅在命中该特定路径时运行。即app.use('/hello', (req, res, next) => { res.send('world'); });当端点“/hello”被命中时将返回“world”,但如果客户端请求“/hi”则不会。app.use((req, res, next) => { res.send('world'); });当您到达任何端点时,as将返回“world”。
您可以用它做更复杂的事情,但这是将中间件附加到您的应用程序的基础知识。它们附加到应用程序的顺序就是它们运行的顺序。
还有一两件事,这将打击你的心,与标准作出了明确的应用程序const app = express()可以也可以作为中间件。这意味着您可以创建多个 express 应用程序,然后使用 app.use 将它们挂载到单个 express 应用程序。这是非常先进的,但确实允许您使用 Express 做一些非常棒的事情。
为什么socket.io中不能访问res.locals?(真正的问题)
在您的中间件处理程序中,您正在设置一个res.locals.use_id属性。这仅适用于该单个请求,只要该请求处于活动状态,您就可以通过将其传递给其他函数来传递它,但在该请求之外它不存在。res实际上是一个响应对象,它告诉 Express 如何响应客户端请求,您可以在请求期间设置它的属性,但是一旦该 HTTP 请求结束,它就消失了。
Socket.io 是一种处理网络套接字请求的方式,而不是标准的 HTTP 请求。因此,在标准的快速 HTTP 请求中,您将无法通过 socket.io 将连接移交给任何东西,因为该连接是一个短暂的 HTTP 请求。同样,您将无法以其他方式做同样的事情。
如果您希望在 socket.io 请求中找到用户 ID,则必须在 socket.io 请求本身中执行此操作。
现在,您正在为 Express.js 请求输入一个中间件,然后调用 next() 来运行下一个 Express 中间件,它在任何时候都不会跨越到 Socket.io 领域。这经常被教程混淆,因为 Socket.io 可以处理 Express 正在侦听的同一端口上的请求,但两者并没有交叉。因此,您需要为 Express.js 请求链和 socket.io 请求链编写单独的中间件。有多种方法可以编写一次此代码,然后编写一个适配器以在两个平台上使用它,但这不是您在这里尝试做的。
我建议你在使用 socket.io 之前只做 nodejs 和表达一段时间,否则你试图一次学习一大堆技术是相当多的尝试和全部使用一次。