相关阅读:
Express 4.X API 翻译[一] -- Application篇
Express 4.X Api 翻译[二] -- Request篇
本篇是Express 4.0 API翻译的第四篇,本篇的内容主要是Router的相关操作。
路由器是一个孤立的中间件和路由的实例。路由器可以被认为是一个”mini”的应用程序,仅能执行中间件和路由选择。每一个Express程序都都会有一个内置的应用路由器。
路由器的行为就像是一个中间件自身一样你可以使用通过应用或者是在其他的路由规则内。
创建一个新的路由器通过使用”express.Router()”
1 var router = express.Router();
路由器可以是有中间件,添加http动态路由就像是一个程序。
1 //适配任何路由规则请传递给这个路由器。 2 router.use(function(req,res,next){ 3 // ... 一些中间的逻辑操作,就像其他的中间件。 4 next(); 5 }); 6 //当处理任何以"/events"结束的请求 7 //取决于路由器在哪里被使用。 8 router.get('/events',function(req,res,next){ 9 //.... 10 });
然后你可以使用一个路由器为一个特定的根URL这样分离您的路由来进入文件甚至是mini 应用。
1 //只有当请求 "/calendar/*"将会被发送到"router" 2 app.use('/calendar',router);
使用被给定的中间件function,带有可选参数的挂载path,默认被挂载在’/’
中间件就像是一个管道,请求开始时从第一个被定义的中间件开始,顺着这个线路一直向下,匹配每一个满足条件的路由。
1 var express = require('express'); 2 var app = express(); 3 var router = express.Router(); 4 5 //一个简单的路由访问日志记录器 6 //所有请求都会首先触及这个中间件 7 router.use(function(req,res,next){ 8 console.log('%s %s %s',req.method,req.url,req.path); 9 next(); 10 }); 11 12 //这个规则将只会被path的结尾为/bar的请求调用 13 router.use('/bar',function(req,res,next){ 14 //...或许这里可以附加一些额外的/bar的日志记录...... 15 next(); 16 }); 17 18 //总是被调用 19 router.use(function(req,res,next){ 20 res.send('Hello World'); 21 }); 22 23 app.use('/foo',router); 24 app.listen(3000);
“绑定”的路径是被剥离的以及中间件函数是不可见的。这主要影响到被绑定的中间件将会在只要后缀确定的情况下,不管前缀是什么样子都会被执行。
这样,中间件使用”router.use()”被”定义”的顺序将会是非常重要的,它们是被顺序调用的,因此这将定义中间件的优先级。例如通常”express.logger()”是您想最先调用的中间件,来记录所有的请求。
1 router.use(logger()); 2 router.use(express.static(__dirname + '/public')); 3 router.use(function(req,res){ 4 res.send('Hello'); 5 });
那么现在假若您不想记录静态文件的请求,但是又想继续记录路由和中间件的请求,你可以简单的将静态文件定义移到logger()上。
1 router.use(express.static(__dirname + '/public')); 2 router.use(logger()); 3 router.use(function(req,res){ 4 res.send('Hello'); 5 });
另一个具体的例子是利用多文件目录提供静态文件服务,给予”/public”的优先级高于其他的目录。
1 app.use(express.static(__dirname + '/public')); 2 app.use(express.static(__dirname + '/files')); 3 app.use(express.static(__dirname + '/uploads'));
逻辑映射到参数。例如当’:user’存在于路由路径,你可以映射用户加载逻辑来自动为这个路由的提供req.user,或者执行参数输入验证。
下面的代码片段说明了callback是如何的像中间件,因此支持异步操作,然而假如这个参数的值在这里被命名为id。企图执行加载用户信息,然后分配给req.user,否则传递一个错误给next(err).
重要的是要意识到任何路由触发了被命名为的参数回调函数将会被顺序执行,如果next没有被传递一个error在上一级。
1 router.param('user',function(req,res,next,id){ 2 User.fine(id,function(err,user){ 3 if(err){ 4 return next(err); 5 } 6 else if(!user){ 7 return next(new Error('failed to load user')); 8 } 9 10 req.user = user; 11 next(); 12 }); 13 }); 14 15 //这个路由使用了被命名为为':user'的参数 16 //这将被导致'user'参数回调函数将会被触发 17 router.get('/users/:user',function(req,res,next){ 18 //req.user 将会在执行到这里时已经被定义 19 //如果这里有任何错误或者是正常的错误处理将会被触发。 20 //这个函数将不会被执行。 21 });
或者你将只传递一个回调函数,在这种情况下,你将有机会改变router.param()的api。例如express-params定义了下面的回调函数,你可以限制参数给定的正则表达式。
这个例子有点先进,检查第二个参数是否为正则表达式,返回一个行为类似于”user”参数例子的回调函数。
1 router.param(function(name,fn){ 2 if(fn instanceof RegExp){ 3 return function(req,res,next,val){ 4 var captures; 5 if(captures = fn.exec(String(val))){ 6 req.params[name] = captures; 7 next(); 8 }else{ 9 next('route'); 10 } 11 } 12 } 13 });
这个方法可以被用来验证参数的有效性,或者可以解析它们到提供的捕捉组。
1 router.param('id',/^\d+$/); 2 3 router.get('/user/:id',function(req,res){ 4 res.send('user' + req.params.id); 5 }); 6 7 router.param('range',/^(\w+)\.\.(\w+)?$/); 8 9 router.get('/range/:range',function(req,res){ 10 var range = req.params.range; 11 res.send('from ' + range[1] + ' to '+ range[2]); 12 });
router.use() 方法还支持命名参数,因此你的其他路由规则挂载点也可以使用这个命名参数。
返回一个路由的一个实例,你可以用于处理HTTP动态请求使用可选的中间件。使用router.route()是一种推荐的方法来避免重复路由命名和拼写错误.。
基于router.param()之前的例子,我们看到router.route()使我们能够容易地指定各种HTTP动态处理程序。
1 var router = express.Router(); 2 3 router.param('user_id',function(req,res,next,id){ 4 //以下是示例用户,可以从数据库....等中获取 5 req.user = { 6 id: id, 7 name:'TJ' 8 }; 9 next(); 10 }); 11 12 router.route('/user/:user_id') 13 .all(function(req,res,next){ 14 //运行在说有http动态请求 15 //可以认为它是特定的路由中间件 16 }) 17 .get(function(req,res,next){ 18 res.json(req.user); 19 }) 20 .put(function(req,res,next){ 21 //仅仅是一个例子,可以是更新用户 22 req.user.name = req.params.name; 23 //保存用户....等 24 res.json(req.user); 25 }) 26 .post(function(req,res,next){ 27 next(new Error('not implemented')); 28 }) 29 .delete(function(req,res,next){ 30 next(new Error('not implemented')); 31 });
该方法重新使用’/users/:user_id’对于不同的HTTP动态请求路径和添加处理程序。
router.VERB()方法提供路由功能在Express,这里的VERB是HTTP动态请求的一中,就好像router.post()。多种回调函数可以被给定,所有的都将被平等对待,这种行为就像是中间件,但不同的是这些”中间件”可以调用next(‘route’)来绕过剩下的回调函数。这种机制可用于执行先决条件路线然后将控制传递给后续的路线当这里没有继续匹配的路线时。
以下代码片段演示了最简单的路由定义。Express将路径转义为正则表达式,在内部使用匹配传入的请求。请求字符串将不被考虑在执行匹配的过程中,例如 “GET /”将会匹配下面的规则,同样”/GET /?name=tobi”将也会被匹配。
1 router.get('/',function(req,res){ 2 res.send('hello world'); 3 });
正则表达式同样可以被使用,如果你有一些特殊的限制,正则表达式会是相当有用的,例如下面的代码将会匹配”GET /commits/71dbb9c” 同样也会匹配”GET /commits/71dbb9c..4c084f9″。
1 router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/,function(req,res){ 2 var from = req.params[0]; 3 var to = req.params[1] || 'HEAD'; 4 res.send('commit range ' + from +'...' + to); 5 });