Nodejs Express 4.X 中文API 4--- Router篇
本篇是Express 4.0 API翻譯的第四篇,本篇的內容主要是Router的相關操作。
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);<span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif;"> </span>
router.use([path],function)
使用被給定的中介軟體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'));
router.param([name],callback)
邏輯對映到引數。例如當’: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() 方法還支援命名引數,因此你的其他路由規則掛載點也可以使用這個命名引數。
router.route(path)
返回一個路由的一個例項,你可以用於處理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(path,[callback...],callback)
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 });