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

loading...


289

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

今天我正在处理我的应用程序并让我的服务器在后台运行 . 我想进行一些更改并刷新页面并立即查看更改 . 具体来说,我正在改变我的布局 . 我无法让它工作,所以我搜索了Stack Overflow的答案,找到了this question . 它说要确保 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');
});

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

So Here Is My Question:

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

3回答

  • 327

    Note: 这描述了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 from route handler”发送到浏览器 .

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

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


    一位评论者还有brought up关于 staticrouter 的顺序的另一点,我没有't addressed: the impact on your app'的整体表现 .

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

    首先使用 router ,匹配路由的请求永远不会到达磁盘,从而节省了宝贵的毫秒数 .

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

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

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

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

    您还可以使用staticCache,它将静态资源缓存在内存中您不必为常用请求的文件命中磁盘 . ( Warning: staticCache will apparently be removed将来 . )

    但是,我不认为 staticCache 缓存否定答案(当文件不存在时),所以它没有 staticCachestaticCache 放在 router 之上而不将其安装到路径上 .

    与所有关于性能的问题一样, measure and benchmark your real-world app (负载下)看看瓶颈究竟在哪里 .


    快递4

    快递4.0 removes 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.


  • 2

    路由意味着确定应用程序如何响应对特定 endpoints 的客户端请求,这是一个URI(或路径)和特定的HTTP请求方法(GET,POST等) . 每个路由都可以有一个或多个处理函数,这些函数在路由匹配时执行 . 在Express 4.0路由器中,我们比以往更灵活地定义路由 . express.Router()多次使用来定义路由组 . 用作中间件来处理请求的路由 . 用作中间件的路由,使用“.param()”验证参数 . 当我们使用app.route()时,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')
    })
    

  • 0

    在快速版本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

    为什么这种方法:

    采用这种方法的主要优点是现在我们的应用更多 modular . 现在,特定路线的所有路线处理程序都可以放入不同的文件中,这使得一切都更易于维护和查找 .

loading...

评论

暂时没有评论!