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

本文翻译自:Node.js / Express.js - How does app.router work?

Before I ask about app.router I think I should explain at least what I think happens when working with middleware. 在我询问app.router之前,我想我应该至少解释一下我在使用中间件时的想法。 To use middleware, the function to use is app.use() . 要使用中间件,要使用的功能是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. 当中间件正在执行时,它将通过使用next()调用下一个中间件,或者使其不再调用中间件。 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. 这意味着我放置中间件调用的顺序很重要,因为某些中间件依赖于其他中间件,而某些中间件甚至可能甚至都没有被调用。

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 . 我无法让它工作,所以我搜索了Stack Overflow的答案并找到了这个问题 It says to make sure that express.static() is beneath require('stylus') . 它说要确保express.static()require('stylus')之下。 But when I was looking at that OP's code, I saw that he had his app.router call at the very end of his middleware calls, and I tried to figure out why that was. 但是当我查看OP的代码时,我看到他在他的中间件调用结束时有他的app.router调用,我试图找出原因。

When I made my Express.js application (version 3.0.0rc4), I used the command express app --sessions --css stylus and in my app.js file the code came setup with my app.router above both the express.static() and require('stylus') calls. 当我做了我Express.js的应用程序(版本3.0.0rc4),我用命令express app --sessions --css stylus在我的app.js文件中的代码来设置与我app.router上述两种express.static()require('stylus')调用。 So it seems like, if it comes already setup that way, then it should stay that way. 所以看起来,如果它已经设置了那样,那么它应该保持这种方式。

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.router in my code. 所以我决定第一步是找出为什么在我的代码中使用app.router很重要。 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). 嗯,也许它有效,因为我从路线文件(routes.index)导出路由。 So next I navigated to /test and it displayed Test on the screen. 接下来我导航到/test并在屏幕上显示Test。 Haha, OK, I have no idea what app.router does. 哈哈,好的,我不知道app.router是做什么的。 Whether it is included in my code or not, my routing is fine. 无论它是否包含在我的代码中,我的路由都很好。 So I am definitely missing something. 所以我肯定错过了一些东西。

So Here Is My Question: 所以这是我的问题:

Could somebody please explain what app.router does, the importance of it, and where I should place it in my middleware calls? 有人可以解释app.router作用,它的重要性,以及我应该把它放在我的中间件调用中的哪个位置? It would also be nice if I got a brief explanation about express.static() . 如果我得到有关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. 据我所知, express.static()是我信息的缓存,如果应用程序找不到请求的页面,它将检查缓存是否存在。


#1楼

参考:https://stackoom.com/question/rGhb/Node-js-Express-js-app-router如何工作


#2楼

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的信息,请参阅本文末尾。


static simply serves files ( static resources) from disk. static只是从磁盘提供文件( 静态资源)。 You give it a path (sometimes called the mount point), and it serves the files in that folder. 你给它一个路径(有时称为挂载点),它提供该文件夹中的文件。

For example, express.static('/var/www') would serve the files in that folder. 例如, express.static('/var/www')将提供该文件夹中的文件。 So a request to your Node server for http://server/file.html would serve /var/www/file.html . 因此,向您的节点服务器请求http://server/file.html将提供/var/www/file.html

router is code that runs your routes. router是运行路由的代码。 When you do app.get('/user', function(req, res) { ... }); 当你做app.get('/user', function(req, res) { ... }); , it is the router that actually invokes the callback function to process the request. ,它是实际调用回调函数来处理请求的router

The order that you pass things to app.use determines the order in which each middleware is given the opportunity to process a request. 将内容传递给app.use的顺序决定了每个中间件有机会处理请求的顺序。 For example, if you have a file called test.html in your static folder and a route: 例如,如果您的静态文件夹和路径中有一个名为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 ? 哪一个被发送到请求http://server/test.html的客户端? Whichever middleware is given to use first. 无论哪个中间件首先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 above the static middleware so that a accidentally-named file can't override one of your routes. 通常,您希望将路由器置于静态中间件之上 ,以便意外命名的文件不能覆盖您的某个路由。

Note that if you don't explicitly use the 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 up another point about the order of static and router that I hadn't addressed: the impact on your app's overall performance. 一位评论者提出了另一个关于staticrouter顺序的观点,我没有提及:对应用程序整体性能的影响。

Another reason to use router above static is to optimize performance. static之上use router另一个原因是优化性能。 If you put static first, then you'll hit the hard drive on every single request to see whether or not a file exists. 如果先放置static ,那么您将在每个请求中点击硬盘驱动器以查看文件是否存在。 In a quick test , I found that this overhead amounted to ~1ms on an unloaded server. 快速测试中 ,我发现在卸载的服务器上这个开销大约为1毫秒。 (That number is much likely to be higher under load, where requests will compete for disk access.) (在负载下,这个数字很可能更高,请求将争夺磁盘访问权限。)

With router first, 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 static to 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 . 在这种情况下,你把它放在router上面。 This avoids processing other middleware/the router if a file is present, but to be honest, I doubt you'll gain that much. 如果文件存在,这可以避免处理其他中间件/路由器,但说实话,我怀疑你会获得那么多。

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. 您还可以使用staticCache ,它将静态资源缓存在内存中,这样您就不必为常用请求的文件命中磁盘。 ( Warning: staticCache will apparently be removed in the future.) 警告: 将来很明显会删除 staticCache 。)

However, I don't think staticCache caches negative answers (when a file does not exist), so it doesn't help if you've put staticCache above router without mounting it to a path. 但是,我不认为staticCache缓存否定答案(当文件不存在时),因此如果您将staticCache放在router上方而不将其安装到路径上,则staticCache

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 removes app.router . Express 4.0 删除了 app.router All middleware ( app.use ) and routes ( app.get et al) are now processed in precisely the order in which they are added. 所有中间件( app.use )和路由( app.get等)现在都按照添加顺序进行处理。

In other words: 换一种说法:

All routing methods will be added in the order in which they appear. 所有路由方法都将按其出现的顺序添加。 You should not do app.use(app.router) . 应该做app.use(app.router) This eliminates the most common issue with Express. 这消除了Express最常见的问题。

In other words, mixing app.use() and app[VERB]() will work exactly in the order in which they are called. 换句话说,混合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. 阅读有关Express 4中更改的更多信息。


#3楼

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). 路由意味着确定应用程序如何响应对特定端点的客户端请求,该请求是URI(或路径)和特定HTTP请求方法(GET,POST等)。 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 4.0路由器中,我们在定义路由方面比以往更灵活。

express.Router() is use multiple times to define groups of routes. express.Router()多次使用来定义路由组。

route used as middleware to process requests. 用作中间件来处理请求的路由。

route used as middleware to validate parameters using ".param()". 用作中间件的路由,使用“.param()”验证参数。

app.route() used as a shortcut to the Router to define multiple requests on a route app.route()用作路由器的快捷方式,用于定义路由上的多个请求

when we are using app.route(), we are attaching our app with that 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')
})

#4楼

In express Version 4 we can easily define routes in the following manner: 在快速版本4中,我们可以通过以下方式轻松定义路径:

server.js: 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: 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;

In server.js we imported the router object of the route.js file 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.js have the following base URL: 现在, route.js中的所有路由都具有以下基本URL:

http://localhost:3000/route HTTP://本地主机:3000 /路由

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. 现在,特定路线的所有路线处理程序都可以放入不同的文件中,这使得一切都更易于维护和查找。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值