Node.js / Express.js - app.router 如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12695591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Node.js / Express.js - How does app.router work?
提问by Aust
Before I ask about app.routerI think I should explain at least what I think happens when working with middleware. To use middleware, the function to use is app.use(). When the middleware is being executed, it will either call the next middleware by using next()or make it so no more middleware get called. That means that the order in which I place my middleware calls is important, because some middleware depends on other middleware, and some middleware near the end might not even be called.
在我询问之前,app.router我认为我应该至少解释一下我认为在使用中间件时会发生什么。要使用中间件,要使用的函数是app.use(). 当中间件被执行时,它要么调用下一个中间件,next()要么让它不再调用中间件。这意味着我放置中间件调用的顺序很重要,因为某些中间件依赖于其他中间件,而接近末尾的某些中间件甚至可能不会被调用。
Today I was working on my application and had my server running in the background. I wanted to make some changes and refresh my page and see the changes immediately. Specifically, I was making changes to my layout. I couldn't get it to work so I searched Stack Overflow for the answer and found this question. It says to make sure that express.static()is beneath require('stylus'). But when I was looking at that OP's code, I saw that he had his app.routercall at the very end of his middleware calls, and I tried to figure out why that was.
今天我正在处理我的应用程序,并让我的服务器在后台运行。我想进行一些更改并刷新我的页面并立即查看更改。具体来说,我正在更改我的布局。我无法让它工作,所以我搜索了 Stack Overflow 的答案并找到了这个问题。它说要确保它express.static()在require('stylus'). 但是当我查看那个 OP 的代码时,我看到他app.router在他的中间件调用的最后有他的调用,我试图弄清楚为什么会这样。
When I made my Express.js application (version 3.0.0rc4), I used the command express app --sessions --css stylusand in my app.js file the code came setup with my app.routerabove both the express.static()and require('stylus')calls. So it seems like, if it comes already setup that way, then it should stay that way.
当我制作 Express.js 应用程序(版本 3.0.0rc4)时,我使用了该命令,express app --sessions --css stylus并且在我的 app.js 文件中,代码与app.router上面的express.static()和require('stylus')调用一起设置。所以看起来,如果它已经设置成这样,那么它应该保持这种状态。
After re-arranging my code so I could see my Stylus changes, it looks like this:
重新安排我的代码以便我可以看到我的 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');
});
So I decided that the first step would be to find out why it is important to even have app.routerin my code. So I commented it out, started my app and navigated to /. It displayed my index page just fine. Hmm, maybe it worked because I was exporting the routing from my routes file (routes.index). So next I navigated to /testand it displayed Test on the screen. Haha, OK, I have no idea what app.routerdoes. Whether it is included in my code or not, my routing is fine. So I am definitely missing something.
所以我决定第一步是找出为什么app.router在我的代码中加入它很重要。所以我把它注释掉,启动我的应用程序并导航到/. 它显示我的索引页就好了。嗯,也许它起作用了,因为我从我的路由文件(routes.index)中导出路由。所以接下来我导航到/test它并在屏幕上显示了测试。哈哈,好吧,我不知道是什么app.router。无论是否包含在我的代码中,我的路由都很好。所以我肯定错过了一些东西。
So Here Is My Question:
所以这是我的问题:
Could somebody please explain what app.routerdoes, the importance of it, and where I should place it in my middleware calls? It would also be nice if I got a brief explanation about express.static(). As far as I can tell, express.static()is a cache of my information, and if the application can't find the requested page, it will check the cache to see if it exists.
有人可以解释一下是什么app.router,它的重要性,以及我应该把它放在我的中间件调用中的什么位置?如果我能得到一个关于express.static(). 据我所知,express.static()是我的信息的缓存,如果应用程序找不到请求的页面,它将检查缓存以查看它是否存在。
回答by josh3736
Note:This describes how Express worked in versions 2 and 3. See the end of this post for information about Express 4.
注意:这描述了 Express 在版本 2 和 3 中的工作方式。有关 Express 4 的信息,请参阅本文末尾。
staticsimply serves files (staticresources) from disk. You give it a path (sometimes called the mount point), and it serves the files in that folder.
static简单地从磁盘提供文件(静态资源)。你给它一个路径(有时称为挂载点),它为该文件夹中的文件提供服务。
For example, express.static('/var/www')would serve the files in that folder. So a request to your Node server for http://server/file.htmlwould serve /var/www/file.html.
例如,express.static('/var/www')将提供该文件夹中的文件。因此,对您的节点服务器的请求http://server/file.html将提供/var/www/file.html.
routeris code that runs your routes. When you do app.get('/user', function(req, res) { ... });, it is the routerthat actually invokes the callback function to process the request.
router是运行您的路线的代码。当您这样做时app.get('/user', function(req, res) { ... });,router实际上是调用回调函数来处理请求。
The order that you pass things to app.usedetermines the order in which each middleware is given the opportunity to process a request. For example, if you have a file called test.htmlin your static folder and a route:
您传递事物app.use的顺序决定了每个中间件有机会处理请求的顺序。例如,如果您test.html在静态文件夹中调用了一个文件和一个路由:
app.get('/test.html', function(req, res) {
res.send('Hello from route handler');
});
Which one gets sent to a client requesting http://server/test.html? Whichever middleware is given to usefirst.
哪一个被发送给请求的客户http://server/test.html?无论哪个中间件use首先被给予。
If you do this:
如果你这样做:
app.use(express.static(__dirname + '/public'));
app.use(app.router);
Then the file on disk is served.
然后提供磁盘上的文件。
If you do it the other way,
如果你反其道而行
app.use(app.router);
app.use(express.static(__dirname + '/public'));
Then the route handler gets the request, and "Hello from route handler" gets sent to the browser.
然后路由处理程序收到请求,并将“Hello from route handler”发送到浏览器。
Usually, you want to put the router abovethe static middleware so that a accidentally-named file can't override one of your routes.
通常,您希望将路由器置于静态中间件之上,以便意外命名的文件无法覆盖您的路由之一。
Note that if you don't explicitly usethe router, it is implicitly added by Express at the point you define a route (which is why your routes still worked even though you commented out app.use(app.router)).
请注意,如果您没有明确use指定router,它会在您定义路线时由 Express 隐式添加(这就是为什么即使您注释掉了您的路线仍然有效app.use(app.router))。
A commenter has brought upanother point about the order of staticand routerthat I hadn't addressed: the impact on your app's overall performance.
一位评论者提出了关于顺序的另一点,static而router我没有提到:对应用整体性能的影响。
Another reason to userouterabove staticis to optimize performance. If you put staticfirst, then you'll hit the hard drive on every single request to see whether or not a file exists. In a quick test, I found that this overhead amounted to ~1ms on an unloaded server. (That number is much likely to be higher under load, where requests will compete for disk access.)
userouter上面的另一个原因static是优化性能。如果你把它static放在第一位,那么你将在每次请求时访问硬盘驱动器以查看文件是否存在。在一个快速测试中,我发现在一个卸载的服务器上这个开销大约为 1 毫秒。(这个数字很可能在负载下更高,请求将竞争磁盘访问。)
With routerfirst, a request matching a route never has to hit the disk, saving precious milliseconds.
有了router第一次,从来没有匹配的路由请求有打盘,节省了宝贵的毫秒。
Of course, there are ways to mitigate static's overhead.
当然,有一些方法可以减轻static的开销。
The best option is to put all of your static resources under a specific folder. (IE /static) You can then mount staticto that path so that it only runs when the path starts with /static:
最好的选择是将所有静态资源放在特定文件夹下。(IE /static) 然后您可以挂载static到该路径,以便它仅在路径以 开头时运行/static:
app.use('/static', express.static(__dirname + '/static'));
In this situation, you'd put this above router. This avoids processing other middleware/the router if a file is present, but to be honest, I doubt you'll gain that much.
在这种情况下,你会把它放在上面router。如果存在文件,这可以避免处理其他中间件/路由器,但老实说,我怀疑您会获得那么多。
You could also use staticCache, which caches static resources in-memory so that you don't have to hit the disk for commonly requested files. (Warning:staticCachewill apparently be removedin the future.)
您还可以使用staticCache,它将静态资源缓存在内存中,这样您就不必为经常请求的文件访问磁盘。(警告:staticCache将来显然会被删除。)
However, I don't think staticCachecaches negative answers (when a file does not exist), so it doesn't help if you've put staticCacheabove routerwithout mounting it to a path.
但是,我认为不会staticCache缓存否定答案(当文件不存在时),因此如果您在没有将其安装到路径的情况下将其放在staticCache上面,则无济于事router。
As with all questions about performance, measure and benchmark your real-world app(under load) to see where the bottlenecks really are.
与所有有关性能的问题一样,测量和基准测试您的实际应用程序(在负载下)以查看真正的瓶颈在哪里。
Express 4
快递4
Express 4.0 removesapp.router. All middleware (app.use) and routes (app.getet al) are now processed in precisely the order in which they are added.
Express 4.0删除了app.router. 所有中间件 ( app.use) 和路由 ( app.getet al ) 现在都按照它们添加的顺序进行处理。
In other words:
换句话说:
All routing methods will be added in the order in which they appear. You should notdo
app.use(app.router). This eliminates the most common issue with Express.In other words, mixing
app.use()andapp[VERB]()will work exactlyin the order in which they are called.app.get('/', home); app.use('/public', require('st')(process.cwd())); app.get('/users', users.list); app.post('/users', users.create);
所有路由方法将按照它们出现的顺序添加。你不应该这样做
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);
回答by Parth Raval
Routing means determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on). Each route can have one or more handler functions, which are executed when the route is matched.
In Express 4.0 Router, we are given more flexibility than ever before in defining our routes.
express.Router() is use multiple times to define groups of routes.
route used as middleware to process requests.
route used as middleware to validate parameters using ".param()".
app.route() used as a shortcut to the Router to define multiple requests on a route
when we are using app.route(), we are attaching our app with that router.
路由意味着确定应用程序如何响应客户端对特定端点的请求,即 URI(或路径)和特定的 HTTP 请求方法(GET、POST 等)。每个路由可以有一个或多个处理函数,当路由匹配时执行。
在 Express 4.0 Router 中,我们在定义路由时获得了前所未有的灵活性。
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')
})
回答by Willem van der Veen
In express Version 4 we can easily define routes in the following manner:
在 express 版本 4 中,我们可以通过以下方式轻松定义路由:
server.js:
服务器.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:
路线.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;
In server.jswe imported the router object of the route.jsfile and apply it in the following manner in server.js:
在server.js我们导入route.js文件的路由器对象并以下列方式应用它server.js:
app.use('/route', route);
Now all of the routes in the route.jshave the following base URL:
现在 中的所有路由route.js都具有以下基本 URL:
Why this approach:
为什么采用这种方法:
The main advantage of taking this approach is that now our app is more modular. All the route handlers for a certain route now can be put into different files which makes everything more maintainable and easier to find.
采用这种方法的主要优点是现在我们的应用程序更加模块化。现在可以将某个路由的所有路由处理程序放入不同的文件中,这使得所有内容都更易于维护且更易于查找。

