1. 程式人生 > 其它 >對中介軟體概念的理解,如何封裝 node 中介軟體

對中介軟體概念的理解,如何封裝 node 中介軟體

一、是什麼

中介軟體(Middleware)是介於應用系統和系統軟體之間的一類軟體,它使用系統軟體所提供的基礎服務(功能),銜接網路上應用系統的各個部分或不同的應用,能夠達到資源共享、功能共享的目的

NodeJS中,中介軟體主要是指封裝http請求細節處理的方法

例如在expresskoaweb框架中,中介軟體的本質為一個回撥函式,引數包含請求物件、響應物件和執行下一個中介軟體的函式

在這些中介軟體函式中,我們可以執行業務邏輯程式碼,修改請求和響應物件、返回響應資料等操作

二、封裝

koa是基於NodeJS當前比較流行的web框架,本身支援的功能並不多,功能都可以通過中介軟體拓展實現。通過新增不同的中介軟體,實現不同的需求,從而構建一個Koa

應用

Koa中介軟體採用的是洋蔥圈模型,每次執行下一個中介軟體傳入兩個引數:

  • ctx :封裝了request 和 response 的變數
  • next :進入下一個要執行的中介軟體的函式

下面就針對koa進行中介軟體的封裝:

Koa的中介軟體就是函式,可以是async函式,或是普通函式

//async函式
app.use(async(ctx,next)=>{
conststart=Date.now();
awaitnext();
constms=Date.now()-start;
console.log(`${ctx.method}${ctx.url}-${ms}ms`);
});

//普通函式
app.use((ctx,next)=>{
conststart=Date.now();
returnnext().then(()=>{
constms=Date.now()-start;
console.log(`${ctx.method}${ctx.url}-${ms}ms`);
});
});

下面則通過中介軟體封裝http請求過程中幾個常用的功能:

token校驗

module.exports=(options)=>async(ctx,next){
try{
//獲取token
consttoken=ctx.header.authorization
if(token){
try{
//verify函式驗證token,並獲取使用者相關資訊
awaitverify(token)
}catch(err){
console.log(err)
}
}
//進入下一個中介軟體
awaitnext()
}catch(err){
console.log(err)
}
}

日誌模組

constfs=require('fs')
module.exports=(options)=>async(ctx,next)=>{
conststartTime=Date.now()
constrequestTime=newDate()
awaitnext()
constms=Date.now()-startTime;
letlogout=`${ctx.request.ip}--${requestTime}--${ctx.method}--${ctx.url}--${ms}ms`;
//輸出日誌檔案
fs.appendFileSync('./log.txt',logout+'\n')
}

Koa存在很多第三方的中介軟體,如koa-bodyparserkoa-static

下面再來看看它們的大體的簡單實現:

koa-bodyparser

koa-bodyparser中介軟體是將我們的post請求和表單提交的查詢字串轉換成物件,並掛在ctx.request.body上,方便我們在其他中介軟體或介面處取值

//檔案:my-koa-bodyparser.js
constquerystring=require("querystring");

module.exports=functionbodyParser(){
returnasync(ctx,next)=>{
awaitnewPromise((resolve,reject)=>{
//儲存資料的陣列
letdataArr=[];

//接收資料
ctx.req.on("data",data=>dataArr.push(data));

//整合資料並使用Promise成功
ctx.req.on("end",()=>{
//獲取請求資料的型別json或表單
letcontentType=ctx.get("Content-Type");

//獲取資料Buffer格式
letdata=Buffer.concat(dataArr).toString();

if(contentType==="application/x-www-form-urlencoded"){
//如果是表單提交,則將查詢字串轉換成物件賦值給ctx.request.body
ctx.request.body=querystring.parse(data);
}elseif(contentType==="applaction/json"){
//如果是json,則將字串格式的物件轉換成物件賦值給ctx.request.body
ctx.request.body=JSON.parse(data);
}

//執行成功的回撥
resolve();
});
});

//繼續向下執行
awaitnext();
};
};

koa-static

koa-static中介軟體的作用是在伺服器接到請求時,幫我們處理靜態檔案

constfs=require("fs");
constpath=require("path");
constmime=require("mime");
const{promisify}=require("util");

//將stat和access轉換成Promise
conststat=promisify(fs.stat);
constaccess=promisify(fs.access)

module.exports=function(dir){
returnasync(ctx,next)=>{
//將訪問的路由處理成絕對路徑,這裡要使用join因為有可能是/
letrealPath=path.join(dir,ctx.path);

try{
//獲取stat物件
letstatObj=awaitstat(realPath);

//如果是檔案,則設定檔案型別並直接響應內容,否則當作資料夾尋找index.html
if(statObj.isFile()){
ctx.set("Content-Type",`${mime.getType()};charset=utf8`);
ctx.body=fs.createReadStream(realPath);
}else{
letfilename=path.join(realPath,"index.html");

//如果不存在該檔案則執行catch中的next交給其他中介軟體處理
awaitaccess(filename);

//存在設定檔案型別並響應內容
ctx.set("Content-Type","text/html;charset=utf8");
ctx.body=fs.createReadStream(filename);
}
}catch(e){
awaitnext();
}
}
}

三、總結

在實現中介軟體時候,單箇中間件應該足夠簡單,職責單一,中介軟體的程式碼編寫應該高效,必要的時候通過快取重複獲取資料

koa本身比較簡潔,但是通過中介軟體的機制能夠實現各種所需要的功能,使得web應用具備良好的可拓展性和組合性

通過將公共邏輯的處理編寫在中介軟體中,可以不用在每一個介面回撥中做相同的程式碼編寫,減少了冗雜程式碼,過程就如裝飾者模式