在我询问 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 文件中,代码在 express.static()
和 require('stylus')
调用上方设置了我的 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()
是我信息的缓存,如果应用程序找不到请求的页面,它会检查缓存是否存在。
注意:这描述了 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”发送到浏览器。
通常,您希望将路由器放在静态中间件之上,以便意外命名的文件无法覆盖您的路由之一。
请注意,如果您没有明确地use
router
,它会在您定义路由时由 Express 隐式添加(这就是即使您注释掉 app.use(app.router)
,您的路由仍然有效的原因)。
一位评论者brought up对 static
和 router
的顺序还有一点我没有提到:对应用程序整体性能的影响。
use
router
高于 static
的另一个原因是优化性能。如果您将 static
放在首位,那么您将在每次请求时点击硬盘驱动器以查看文件是否存在。在 quick test 中,我发现此开销在未加载的服务器上约为 1 毫秒。 (这个数字在负载下很可能会更高,因为请求将竞争磁盘访问。)
首先使用 router
,匹配路由的请求永远不必访问磁盘,从而节省宝贵的毫秒数。
当然,有一些方法可以减轻 static
的开销。
最好的选择是将所有静态资源放在特定文件夹下。 (IE /static
)然后您可以将 static
安装到该路径,以便它仅在路径以 /static
开头时运行:
app.use('/static', express.static(__dirname + '/static'));
在这种情况下,您可以将其置于 router
之上。如果文件存在,这可以避免处理其他中间件/路由器,但老实说,我怀疑你会获得那么多。
您还可以使用 staticCache
,它将静态资源缓存在内存中,这样您就不必为经常请求的文件访问磁盘。 (警告: staticCache
will 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.
路由意味着确定应用程序如何响应客户端对特定端点的请求,该端点是 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')
})
在 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!'));
路由.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:
为什么采用这种方法:
采用这种方法的主要优点是现在我们的应用程序更加模块化。现在可以将某个路由的所有路由处理程序放入不同的文件中,这使得所有内容都更易于维护和查找。
An article 由 @kelyvinn 从 2016 年开始,旨在展示模块化,包括以下代码:
// 控制器/apis/dogs/index.js const express = require('express'), dogService = require('../../../services/dogs');让路由器 = express.Router(); router.get('/', dogService.getDogs); router.get('/:id', dogService.getDogWithId); module.exports = 路由器;
router
放在一个地方。如果在您第一次调用app.get
(或post
或其他人)时,您还没有use
dapp.router
,Express 会为您添加它。router
之后使用static
,关于其他中间件的问题变得无关紧要,因为它必须在路由器之上。app.router
是当前 master 分支中的 removed,即 express-4.0。每条路由都成为一个单独的中间件。