淺析Express中的路由與應用模式

1. ? 引言

? ? ? ? Express是一個基于Node.js的輕量級web開發(fā)框架,具有體積小,使用靈活等特點。查看Express的源碼,如果不計供使用的中間件,主體框架只有一千余行代碼,非常簡練。

? ? ? ? Express模型的核心為Express中定義的路由和路由器。分析Express源碼可發(fā)現(xiàn)Express的路由提供多種靈活的應用模式。

? ? ? ? ?我們首先介紹一下Express中的路由、路由器相關概念、結構及其特點,然后針對典型場景描述使用Express路由的四種應用模式。

2. Express中的路由與路由器

? ? ? ? Express具有典型的MVC模型特征。我們將路由定義為一個二元組route=(path, endpoint):其中path為HTTP請求的路徑,endpoint為請求路徑應映射到的端點(端點可視為處理該請求的實體),則Express中的路由器負責將請求映射到對應端點進行處理。

? ? ? ?Express中的路由器分為兩種類型:

? ? ? ?app類型的路由器常使用如下代碼創(chuàng)建:


var express =require('express');

var app = express();


? ? ? ? router類型的路由器常使用如下代碼創(chuàng)建:


??var express = require('express');

var router =express.Router();


? ? ? ? ? app和router是形為function(request, response, next)形式的函數(shù)對象,使用app.verb(),router.verb()形式函數(shù)實現(xiàn)路由注冊(路由注冊本質上是一個觀察者模式)。

? ? ? ? app.verb()和router.verb()中的verb常使用use、get、post、put、delete、route等動詞,不同動詞管轄的HTTP請求方法范圍不同,這些動詞函數(shù)的參數(shù)形式常為(pathExp, handleCallback)形式:其中pathExp表示請求路徑,可為正則表達式;handleCallback為路徑映射處理函數(shù)。

? ? ? ?app是Express框架所構建程序的請求處理入口,app可作為頂層路由器使用,在應用中也可掛載下級路由器(使用router對象)以實現(xiàn)分級路由。其間的關系可由圖1表示:


圖 1

? ? ? ? 考察如下代碼:


app.use('/reports', router1);

router1.get('/querymysql/:id', queryMysqlData,handleQueryData);


? ? ? ? 對于http請求URL“/reports/querymysql/1”,Express中的路由器將此請求路由到queryMysqlData函數(shù)處理。

3. ? Express中的路由應用模式

3.1. ?REST模式

? ? ? ? 對于一個使用restful風格的應用, 讓我們想一想在不使用Express的時候如何在Node.js中處理rest請求,我們常常會寫下如下示例代碼:


var server = http.createServer(function (request,response) {

???? switch(request.url) {

???????????????????case 'uri1'

???????????????????????handleUri1 (request, response);

???????????????????????break;

???????????????????case ' uri2'

???????????????????????handleU ri2(request, response);

???????????????????????break;

???????????????????case ' uri3'

???????????????????????handleU ri3 (request, response);

???????????????????????break;

???????????????????case ' uri4'

???????????????????????handleU ri4 (request, response);

???????????????????????break;

???????????????????...

???????????????????default:

???????????????????????logToConsole('unknown path:' + path);

???????????????????????response.writeHead(404);

???????????????????????response.end("404 Not found");

???????????????????????break;

???????????????}

}


? ? ? ? Express將上面代碼中對每個rest資源的操作(switch分支)轉換為路由,路由中的路徑為rest資源的URI,處理端點為function(request, response,next)形式、對rest資源的操作函數(shù)。

? ? ? ? 常使用app.route函數(shù)實現(xiàn)一個完整的restful接口,如下示例代碼:


app.route('/uri1')

? .get(function(req,res) {

??? handleGetUri1();

? })

.post(function(req, res) {

??? handlePost Uri1();

? })

?.put(function(req, res) {

??? handlePut Uri1();

? })

.delete(function(req, res) {

??? handleDeleteUri1();

? });


3.2. ?AOP模式

? ? ? ? 在處理不同路徑的HTTP請求時,常常需要在請求處理前和處理后做一些通用操作,這種應用需求是一個典型的AOP應用要求。

? ? ? ? Express中允許定義一個具有通配路徑的路由,在調用其它路徑的路由前會先調用該通配路徑路由。此通配路徑路由也成為其它路徑路由切面的一個注入點,考察如下示例代碼:


router.use(function timelog(req,res,next){

???console.log("receive report request time is:",Date.now());

??? next(); //注意next函數(shù)的使用,必須聲明該函數(shù)才能調用后繼映射函數(shù)

});

router.get('/chart1', proxy({

??? target:'http://127.0.0.1:8082',

???changeOrigin: true,

??? pathRewrite:{

???????'^/reports/chart1': '/loadChart1'

??? }

}));?

router.get('/querymysql/:id', queryMysqlData,handleQueryData);


? ? ? ? 上述代碼中,在執(zhí)行router的'/chart1'路由和'/querymysql/:id'路由之前都會執(zhí)行timelog函數(shù),在日志中記錄當前路由執(zhí)行時間。

3.3. ? 責任鏈模式

? ? ? ? 在Node.js中,由于多使用異步函數(shù),常會出現(xiàn)異步回調函數(shù)中嵌套異步回調函數(shù)的情形。當出現(xiàn)多重異步回調時,則代碼會變得混亂和難以維護。

? ? ? ? 考察一個應用場景:應用需要在數(shù)據(jù)庫中進行多次查詢,并對多次查詢的結果綜合處理。若使用數(shù)據(jù)庫提供的異步查詢接口,則需要在前一個查詢操作的回調函數(shù)中進行下一個查詢操作,若寫在一個回調函數(shù)中,代碼顯臃腫。

? ? ? ? Express的一個路由可定義多個處理函數(shù),這些處理函數(shù)可設計為鏈式調用,實現(xiàn)了責任鏈模式,考察如下代碼:


app.get('/test',function(req,res,next){

??? handle1();

??? next();

},function(req,res,next){

??? handle2();

??? next();

},function(req,res,next){

?? handle3();

});


? ? ? ? 上述代碼中:handle1, handle2, handle3構成了一個處理責任鏈“handle1->handle2->handle3”,通過next函數(shù)指引鏈式調用。

? ? ? ? Express中路由的責任鏈應用特性使得多重異步嵌套的代碼變得清晰和優(yōu)雅。

? ? ? ? ?針對本節(jié)開始提到的數(shù)據(jù)庫查詢應用場景,下面的示例代碼展示了責任鏈模式的應用特點。


router.get('/querymysql/:id',queryMysqlData, handleQueryData);

//查詢mysql表中的數(shù)據(jù)

functionqueryMysqlData(req, res, next) {

??? if ("id" in req.params) {

??????? dbpool.query(" select * fromarticles where id=?" ,[req.params.id], function (err, rows, fields) {

??????????? if (err) {

??????????????? res.send(err.stack);

??????????? } else {

??????????????? if (rows && rows.length> 0) {

??????????????????? console.log('The queriedrows is: ', rows.length);

??????????????????? res.articles = rows;

??????????????????? next();

??????????????? } else {

??????????????????? res.send("no queryresults!");

??????????????? }

??????????? }

??????? });

??? } else {

??????? res.send("invalid queryparams!");

??? }

}

//處理查詢mysql后得到的數(shù)據(jù)

functionhandleQueryData(req, res) {

??? if ("articles" in res) {

??????? res.send("id:" +req.params.id + ";title:" + res.articles[0].title);

??? }else{

??????? res.send("no query datahandled!");

??? }

}


3.4. ?熔斷器模式

? ? ? ? 上節(jié)提到的責任鏈模式本質上是一個逐級調用模型。在分布式服務架構(微服務架構)中,深度調用常常需要考慮調用可達性問題,即需要考慮某級調用會否一直不響應。調用可達性問題常使用熔斷器模式,即在調用端設置一個熔斷器,熔斷條件產(chǎn)生時,熔斷器發(fā)生熔斷,返回給調用方調用失敗信息。

? ? ? ? 考慮這樣的應用場景:對于一些有處理時間要求的請求,當在指定時間內沒有完成處理,需要向請求方返回處理失敗信息。針對此應用場景,可在Express路由中設置超時熔斷器,當處理超時,開啟熔斷器,通知請求方本次處理請求失敗。

? ? ? ? 上述應用場景可使用如下示例代碼應對:


app.get('/circuit',function(req, res, next){

?? ?var bt=setTimeout(function () {

???????next('route'); //觸發(fā)熔斷

??? },3000); //設置熔斷時間為3

?? res.breakTimer= bt;

?? next();

},function(req,res,next){

??? handle2();

??? next();

},function(req,res,next){

?? handle3();

?? clearTimeout(res.breakTimer);//正常執(zhí)行完畢,取消熔斷定時器

});

app.get('/circuit ',function(req,res,next){

? if(!res.finished){//如果還沒有響應,啟動熔斷

??? //返回給調用者熔斷信息

???res.send("breakCondition is true, notify the invoker.");

? }

});


4. ? 小結

? ? ? ? 本文介紹了Express框架中路由和路由器的概念、結構和特點,并針對典型應用場景歸納了REST、AOP、責任鏈、熔斷器四種應用模式,可用于應用開發(fā)中的一些常用場景。

5. ?參考文獻

1.http://expressjs.com/

2.http://www.runoob.com/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容