Node.js/Express.js - app.router如何工作?

Aus*_*ust 295 middleware node.js express

在我问起之前我app.router想我应该至少解释一下我在使用中间件时的想法.要使用中间件,要使用的功能是app.use().当中间件被执行时,它将通过使用next()或调用下一个中间件来调用,因此不再调用中间件.这意味着我放置中间件调用的顺序很重要,因为某些中间件依赖于其他中间件,而某些中间件甚至可能甚至都没有被调用.

今天我正在处理我的应用程序并让我的服务器在后台运行.我想进行一些更改并刷新页面并立即查看更改.具体来说,我正在改变我的布局.我无法让它工作,所以我搜索了Stack Overflow的答案并找到了这个问题.它说要确保它express.static()在下面require('stylus').但当我查看OP的代码时,我看到他app.router在他的中间件调用结束时接到了他的电话,我试图找出原因.

当我创建我的Express.js应用程序(版本3.0.0rc4)时,我使用了该命令,express app --sessions --css stylus并在我的app.js文件中设置了app.router上面的代码express.static()require('stylus')调用代码.所以看起来,如果它已经设置了那样,那么它应该保持这种方式.

重新安排我的代码后,我可以看到我的Stylus更改,它看起来像这样:

app.configure(function(){
  //app.set() calls
  //app.use() calls
  //...
  app.use(app.router);
  app.use(require('stylus').middleware(__dirname + '/public'));
  app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});

app.get('/', routes.index);

app.get('/test', function(req, res){
  res.send('Test');
});
Run Code Online (Sandbox Code Playgroud)

所以我决定第一步是找出为什么app.router在我的代码中有重要性.所以我评论了它,开始我的应用程序并导航到/.它显示我的索引页面就好了.嗯,也许它有效,因为我从路线文件(routes.index)导出路由.接下来我导航到/test屏幕上显示Test.哈哈,好的,我不知道是什么app.router.无论它是否包含在我的代码中,我的路由都很好.所以我肯定错过了一些东西.

所以这是我的问题:

有人可以解释一下app.router它的重要性,它的重要性,以及我应该把它放在我的中间件调用中的哪个位置?如果我得到一个简短的解释,那也很好express.static().据我所知,express.static()是我的信息缓存,如果应用程序找不到请求的页面,它将检查缓存以查看它是否存在.

jos*_*736 328

注意:这描述了Express在版本2和3中的工作方式.有关Express 4的信息,请参阅本文末尾.


static只是从磁盘提供文件(静态资源).你给它一个路径(有时称为挂载点),它提供该文件夹中的文件.

例如,express.static('/var/www')将提供该文件夹中的文件.所以到您的节点服务器的请求,http://server/file.html将有助于/var/www/file.html.

router是运行您的路线的代码.当你这样做时app.get('/user', function(req, res) { ... });,它router实际上是调用回调函数来处理请求.

您传递app.use的顺序决定了每个中间件有机会处理请求的顺序.例如,如果您test.html在静态文件夹和路径中调用了一个文件:

app.get('/test.html', function(req, res) {
    res.send('Hello from route handler');
});
Run Code Online (Sandbox Code Playgroud)

哪一个被发送到客户请求http://server/test.html?无论哪个中间件都是use第一个.

如果你这样做:

app.use(express.static(__dirname + '/public'));
app.use(app.router);
Run Code Online (Sandbox Code Playgroud)

然后提供磁盘上的文件.

如果你这样做,

app.use(app.router);
app.use(express.static(__dirname + '/public'));
Run Code Online (Sandbox Code Playgroud)

然后路由处理程序获取请求,并将"Hello from route handler"发送到浏览器.

通常,您希望将路由器置于静态中间件之上,以便意外命名的文件不能覆盖您的某个路由.

请注意,如果您没有明确use指出router,则在您定义路径时,Express会隐式添加它(这就是为什么即使您注释掉了,您的路线仍然有效app.use(app.router)).


一个评论者提出了有关的顺序不同的另一点staticrouter我没有解决:在你的应用程序的整体性能的影响.

use router上面的另一个原因static是优化性能.如果static先放入,那么您将在每个请求中点击硬盘驱动器以查看文件是否存在.在快速测试中,我发现在卸载的服务器上这个开销大约为1毫秒.(在负载下,这个数字很可能更高,请求将争夺磁盘访问权限.)

有了router第一次,从来没有匹配的路由请求有打盘,节省了宝贵的毫秒.

当然,有一些方法可以减轻static开销.

最好的选择是将所有静态资源放在特定文件夹下.(IE /static)然后static,您可以安装到该路径,以便它仅在路径以下开头时运行/static:

app.use('/static', express.static(__dirname + '/static'));
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你把它放在上面router.如果文件存在,这可以避免处理其他中间件/路由器,但说实话,我怀疑你会获得那么多.

您还可以使用staticCache,它将静态资源缓存在内存中,这样您就不必为常用请求的文件命中磁盘.(警告: staticCache 将来显然会被删除.)

但是,我不认为staticCache缓存负面答案(当文件不存在时),所以如果你把它放在staticCache上面router而不将它安装到路径上它就无济于事.

与所有关于性能的问题一样,测量和测试您的真实应用程序(负载下)以查看瓶颈的真正位置.


快递4

Express 4.0 删除 app.router.现在,所有中间件(app.use)和路由(app.get等)都按照添加顺序进行处理.

换一种说法:

所有路由方法都将按其出现的顺序添加.你不应该这样app.use(app.router).这消除了Express最常见的问题.

换句话说,混合app.use()并将完全按照它们被调用的顺序app[VERB]()工作.

app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);
Run Code Online (Sandbox Code Playgroud)

阅读有关Express 4中更改的更多信息.

  • @MikeCauser:不,因为磁盘访问的开销(查看文件是否存在)大于函数调用的开销.在我的[测试](https://gist.github.com/daguej/5100313)中,在卸载的服务器上,此开销达1毫秒.在负载下,这很可能会更高,其中请求将竞争磁盘访问.对于`router`之后的`static`,关于其他中间件的问题变得无关紧要,因为它*必须*在路由器之上. (4认同)
  • 当前主分支中的'app.router`被[删除](https://github.com/visionmedia/express/pull/1909),这将是[express-4.0](https://github.com/visionmedia) /快递/问题/ 1838).每条路由都成为一个独立的中间件. (3认同)
  • 当我使用它时,还有一个澄清.在快递4中,可以将多个路由分配给路由器,然后使用路由器,路由器被赋予根路径并通过app.use(路径,路由器)放置在"中间件"堆栈中.这允许每个相关路由使用它们自己的路由器并被分配基本路径作为一个单元.如果我更好地理解它,我会提议发布另一个答案.我再次从http://scotch.io/tutorials/javascript/learn-to-use-the-new-router-in-expressjs-4获取此信息 (3认同)
  • `router`在一个地方.如果,第一次调用`app.get`(或`post`或其他),你还没有`use`d`app.router`,Express会为你添加它. (2认同)
  • 精彩的解释!非常感谢! (2认同)