对于您如何以及为什么设置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);
我希望能够在socket.js模型中访问res.locals,就像在routes文件夹中找到的index.js中一样。
我猜不出该怎么做。如果有人能够解释我为什么以及为什么不能,那将是一个好处。谢谢!
答案 0 :(得分:0)
欢迎使用Expressjs,您可能需要进一步研究一些基础知识,它们将有助于解决您的一些困惑。我将对它们进行简要说明,但建议您做进一步的研究。然后,我会在最后回答您的实际问题。
中间件和应用程序使用
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路径)都运行,而后者(具有特定路径)仅在命中特定路径时运行。即当命中端点“ / hello”时,app.use('/hello', (req, res, next) => { res.send('world'); });
将返回“ world”,但是如果客户端请求“ / hi”,则不会。当您碰到任何端点时,app.use((req, res, next) => { res.send('world'); });
将返回“世界”。
您可以执行更复杂的操作,但这是将中间件附加到应用程序的基础。它们附加到应用程序的顺序就是它们运行的顺序。
还有一件事,这会让您大吃一惊,使用标准const app = express()
制作的快速应用程序也可以用作中间件。这意味着您可以创建多个快速应用程序,然后使用app.use将它们安装到单个快速应用程序。这是相当先进的,但是确实可以让您用Express做一些很棒的事情。
为什么不能在socket.io中访问res.locals? (真正的问题)
在中间件处理程序中,您正在设置res.locals.use_id
属性。这仅与单个请求一起存在,只要可以将请求传递给其他函数,就可以传递该请求,但在该请求之外不存在。 res
实际上是告诉Express响应客户端请求的响应对象,您可以在请求期间设置其属性,但是一旦HTTP请求结束,它就消失了。
Socket.io是一种处理Web套接字请求而不是标准HTTP请求的方法。因此,在标准的快速HTTP请求中,您将无法使用socket.io切换到任何内容的连接,因为该连接是一个短暂的HTTP请求。同样,您将无法以其他方式执行相同操作。
如果您希望在socket.io请求中找到用户ID,则必须在socket.io请求本身中进行操作。
现在,您正在为Express.js请求输入一个中间件,然后调用next()来运行下一个表达中间件,它永远不会跨入Socket.io领域。由于Socket.io可以在Express正在侦听的同一端口上处理请求,因此教程经常将其混淆。因此,您将需要为Express.js请求链和socket.io请求链编写单独的中间件。有一种方法可以编写一次此代码,然后编写适配器以在两个平台上使用,但这不是您在此处尝试做的。
我建议您在使用socket.io之前也只看一下nodejs并表达一段时间,否则您尝试一次学习全部技术是很多尝试并立即全部加入。