路由器是一個孤立的中間件和路由的實例。路由器能夠被認爲是一個」mini」的應用程序,僅能執行中間件和路由選擇。每個Express程序都都會有一個內置的應用路由器。html
路由器的行爲就像是一箇中間件自身同樣你可使用經過應用或者是在其餘的路由規則內。正則表達式
建立一個新的路由器經過使用」express.Router()」數據庫
1 var router = express.Router();
路由器能夠是有中間件,添加http動態路由就像是一個程序。express
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 應用。json
1 //只有當請求 "/calendar/*"將會被髮送到"router" 2 app.use('/calendar',router);
使用被給定的中間件function,帶有可選參數的掛載path,默認被掛載在’/’api
中間件就像是一個管道,請求開始時從第一個被定義的中間件開始,順着這個線路一直向下,匹配每個知足條件的路由。app
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()上。post
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 });