【问题标题】:Node.js / Express.js - How does app.router work?Node.js / Express.js - app.router 是如何工作的?
【发布时间】:2012-09-23 14:52:02
【问题描述】:

在我询问app.router 之前,我想我至少应该解释一下我认为在使用中间件时会发生什么。要使用中间件,要使用的函数是app.use()。当中间件被执行时,它要么使用next() 调用下一个中间件,要么让它不再调用中间件。这意味着我放置中间件调用的顺序很重要,因为一些中间件依赖于其他中间件,而接近末尾的一些中间件甚至可能不会被调用。

今天我正在处理我的应用程序并让我的服务器在后台运行。我想进行一些更改并刷新我的页面并立即查看更改。具体来说,我正在更改我的布局。我无法让它工作,所以我在 StackOverflow 上搜索了答案并找到了 this question。它说要确保express.static()require('stylus') 之下。但是当我查看那个 OP 的代码时,我看到他在中间件调用的最后有他的 app.router 调用,我试图弄清楚为什么会这样。

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

重新安排我的代码以便我可以看到我的 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');
});

所以我决定第一步是找出为什么在我的代码中包含app.router 很重要。所以我把它注释掉了,启动了我的应用程序并导航到/。它很好地显示了我的索引页面。嗯,也许它起作用了,因为我正在从我的路由文件 (routes.index) 导出路由。所以接下来我导航到/test,它在屏幕上显示了测试。哈哈,好吧,我不知道app.router 做了什么。无论它是否包含在我的代码中,我的路由都很好。所以我肯定错过了一些东西。

这是我的问题:

有人能解释一下app.router 的作用、它的重要性以及我应该将它放在我的中间件调用中的什么位置吗?如果我能得到关于express.static() 的简要解释,那也很好。据我所知,express.static() 是我信息的缓存,如果应用程序找不到请求的页面,它会检查缓存是否存在。

【问题讨论】:

  • 感谢您提出这个问题。我一直在谷歌上搜索这个答案(以及提示它的问题)。
  • 这是一个写得很好的问题,我在谷歌上搜索同样的东西。

标签: node.js middleware express


【解决方案1】:

注意:这描述了 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');
});

哪一个被发送给请求http://server/test.html的客户?无论哪个中间件先给use

如果你这样做:

app.use(express.static(__dirname + '/public'));
app.use(app.router);

然后提供磁盘上的文件。

如果换一种方式,

app.use(app.router);
app.use(express.static(__dirname + '/public'));

然后路由处理程序获取请求,并将“来自路由处理程序的Hello”发送到浏览器。

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

请注意,如果您没有明确地 userouter,它会在您定义路由时由 Express 隐式添加(这就是即使您注释掉了 app.use(app.router),您的路由仍然有效的原因)。


一位评论者对brought up 提出了关于staticrouter 的顺序的另一点我没有解决的问题:对应用整体性能的影响。

userouter 高于static 的另一个原因是优化性能。如果您将static 放在首位,那么您将在每个请求上点击硬盘驱动器以查看文件是否存在。在quick test 中,我发现此开销在未加载的服务器上总计约为 1 毫秒。 (这个数字在负载下​​可能会更高,因为请求将竞争磁盘访问。)

首先使用router,匹配路由的请求永远不必访问磁盘,从而节省宝贵的毫秒时间。

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

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

app.use('/static', express.static(__dirname + '/static'));

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

您也可以使用staticCache,它将静态资源缓存在内存中,这样您就不必为经常请求的文件访问磁盘。 (警告:staticCachewill apparently be removed 未来。)

但是,我认为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);

Read more about changes in Express 4.

【讨论】:

  • router 放在一个地方。如果您第一次致电app.get(或post 或其他人),您还没有used app.router,Express 会为您添加。
  • @MikeCauser:不,因为磁盘访问的开销(查看文件是否存在)大于函数调用的开销。在我的test 中,空载服务器上的开销总计为 1 毫秒。在负载下,这很可能会更高,因为请求将竞争磁盘访问。在router 之后使用static,关于其他中间件的问题变得无关紧要,因为它必须在路由器之上。
  • 精彩的解释!非常感谢!
  • app.router 在当前 master 分支中是 removed,它将是 express-4.0。每条路由都成为一个单独的中间件。
  • 再澄清一下,因为我正在处理这个问题。在 express 4 中,可以将多个路由分配给一个路由器,然后为了使用该路由器,路由器被赋予一个根路径,并通过 app.use(path, router) 放置在“中间件”堆栈中。这允许相关路由各自使用自己的路由器,并被分配一个基本路径作为一个单元。如果我能更好地理解它,我会提出另一个答案。同样,我从scotch.io/tutorials/javascript/… 得到这个
【解决方案2】:

路由意味着确定应用程序如何响应客户端对特定端点的请求,该端点是 URI(或路径)和特定的 HTTP 请求方法(GET、POST 等)。 每个路由可以有一个或多个处理函数,当路由匹配时执行。

在 Express 4.0 路由器中,我们在定义路由方面获得了前所未有的灵活性。

express.Router() 被多次使用来定义路由组。

路由用作处理请求的中间件。

路由用作中间件以使用“.param()”验证参数。

app.route() 用作 Router 的快捷方式,在路由上定义多个请求

当我们使用 app.route() 时,我们正在将我们的应用与那个路由器连接起来。

var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS. 
app.get('/', function (req, res) {
  res.render('index');  
})
app.get('/test', function (req, res) {
  res.send('test')
})

【讨论】:

    【解决方案3】:

    在 express 版本 4 中,我们可以通过以下方式轻松定义路由:

    server.js:

    const express = require('express');
    const app = express();
    const route = require('./route');
    
    app.use('/route', route);
    // here we pass in the imported route object
    
    app.listen(3000, () => console.log('Example app listening on port 3000!'));
    

    route.js:

    const express = require('express');
    const router = express.Router();
    
    router.get('/specialRoute', function (req, res, next) {
         // route is now http://localhost:3000/route/specialRoute
    });
    
    router.get('/', function (req, res, next) {
        // route is now http://localhost:3000/route
    });
    
    module.exports = router;
    

    server.js中我们导入了route.js文件的路由对象,并在server.js中以如下方式应用:

    app.use('/route', route);
    

    现在route.js 中的所有路由都具有以下基本 URL:

    http://localhost:3000/route

    为什么采用这种方法:

    采用这种方法的主要优点是现在我们的应用更加模块化。现在可以将某个路由的所有路由处理程序放入不同的文件中,这使得一切都更易于维护和查找。

    【讨论】:

      【解决方案4】:

      An article @kelyvinn 从 2016 年开始,旨在展示模块化,包括以下代码:

      // controllers/apis/dogs/index.js
      const
          express = require('express'),
          dogService = require('../../../services/dogs');
      
      let router = express.Router();
      
      router.get('/', dogService.getDogs);
      router.get('/:id', dogService.getDogWithId);
      
      module.exports = router;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-28
        • 2012-03-18
        • 1970-01-01
        • 1970-01-01
        • 2012-03-17
        • 2012-09-19
        • 2012-06-26
        相关资源
        最近更新 更多