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

时间:2012-10-02 17:53:48

标签: node.js middleware express

在我询问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()的代码1}}和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做了什么。无论它是否包含在我的代码中,我的路由都很好。所以我肯定错过了一些东西。

所以这是我的问题:

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

4 个答案:

答案 0 :(得分: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');
});

哪一个发送给请求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 router,则会在您定义路线时由Express隐式添加(这就是为什么即使您注释掉了{ {1}})。


评论者对app.use(app.router)static的订单brought up提出了quick test另一点,我没有提及:对应用整体效果的影响。

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

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

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

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

/static

在这种情况下,您将其置于app.use('/static', express.static(__dirname + '/static')); 之上。如果文件存在,这可以避免处理其他中间件/路由器,但说实话,我怀疑你会获得那么多。

您还可以使用will apparently be removed,它会在内存中缓存静态资源,这样您就不必为常用请求的文件访问磁盘。 (警告: router Read more about changes in Express 4.将来。)

但是,我不认为staticCache缓存否定答案(当文件不存在时),因此如果您将staticCache置于staticCache之上,则无效将它安装到路径上。

与所有关于效果的问题一样,衡量和衡量您的真实世界应用(负载下)以了解瓶颈的真正含义。


Express 4

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

换句话说:

  

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

     

换句话说,混合app.use(app.router)app.use()将按照调用它们的顺序完全

app[VERB]()

{{3}}

答案 1 :(得分:2)

  

路由意味着确定应用程序如何响应对特定端点的客户端请求,该请求是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')
})

答案 2 :(得分: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

为什么要这样做:

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

答案 3 :(得分:0)

An article@kelyvinn于2016年发布,旨在演示模块化,包括以下代码:

version: '3.7'

services:
    web:
        build:
            context: ./webapp
            dockerfile: Dockerfile.prod
        # build: ./webapp
        tty: true
        command: gunicorn --workers=2 --threads=4 main.wsgi:application --bind 0.0.0.0:8000
        volumes:
            - /media/ftp/:/media/alfacenter/
            - static_volume:/home/dodo/webapp/web/staticfiles
        expose:
            - 8000
        env_file:
            - ./.env.prod
    nginx:
        build: ./nginx
        ports:
            - 80:80
        volumes:
            - static_volume:/home/dodo/webapp/web/staticfiles
        depends_on:
            - web
volumes:
    static_volume: