中介軟體寫法
根據我們前文的分析,中介軟體通常為以下形式:
async (ctx, next) => {....}
複製程式碼
一般來說中介軟體有自己的配置,所以我們總結出來一種通用的中介軟體寫法,我們通過傳入配置的方式可以返回根據配置定製的中介軟體:
// 通用中介軟體寫法
module.exports = function(options) {
// 配置處理
return aysnc (ctx, next) => {
// 中介軟體邏輯...
}
}
複製程式碼
使用方式:
app.use(middleware(options)) // middleware(options)返回一箇中介軟體
複製程式碼
除此之外,還有另一種中介軟體寫法。正如前文分析的一樣,koa-compose可以將多箇中介軟體合成一箇中介軟體,那麼我們也可將有關聯的中介軟體合成一個大的中介軟體,寫法如下:
app.use(compose([middleware1, middleware2, ...]))
複製程式碼
常見中介軟體
Koa是基於中介軟體模式的,但是框架本身並不包含任何中介軟體。在實際的開發當中,我們可以通過組合中介軟體進行功能的實現。Koa中常見的中介軟體如下:
- Koa-router:Koa-router的實現機制與koa本身的實現類似,都是分為兩個階段,初始化階段和執行階段。初始化階段主要涉及到路由的註冊,執行階段為尋找到匹配的路由,然後使用compose函式合成一箇中介軟體,執行該中介軟體。一個例子說明:
var Koa = require(`koa`);
var Router = require(`koa-router`);
var app = new Koa();
var router = new Router();
router.get(`/`, (ctx, next) => {}); // 註冊路由
app.use(router.routes()) // 返回匹配路由的複合中介軟體
.use(router.allowedMethods());
複製程式碼
感興趣的也可以參看原始碼,簡單易懂
- Koa-bodyparser
前文中講過,node只會對header進行解析,header解析之後便傳送一個request事件,body資料獲取需要自己對req(incomingMessage)上的data和end事件進行監聽。
const http = require(`http`);
http.createServer((req , res)=>{
console.log(`request here.`);
let data = ``;
req.on(`data`,(chunk)=>{
data += chunk;
});
req.on(`end`,()=>{
console.log(`data:`,data);
});
}).listen(3000,`127.0.0.1`);
複製程式碼
bodyparser中介軟體的作用就是獲取body資料並按照想要的格式進行解析,將解析後的資料賦值給ctx.body。
app.use(bodyParser(options));
複製程式碼
- Koa-static:為靜態資源訪問建立一個伺服器,根據url訪問對應的資料夾、檔案
- Koa-ejs:使用ejs渲染服務端模板
更多中介軟體請參考koa官方清單:https://github.com/koajs/koa/wiki
自己寫中介軟體
說了這麼多中介軟體,我們以自己寫一箇中介軟體作為該篇結束。以下示例為一個現實中的例子,做了一部分精簡。問題的背景為,網站經常被某些ip攻擊,影響業務正常執行,於是做了一箇中介軟體進行ip的過濾,對於ip黑名單上的ip一律拒絕進一步處理請求。希望通過這個示例,能夠使大家進一步瞭解中介軟體的作用。
/*
** iplimiter: ip過濾中介軟體,對於在ip黑名單上的ip直接返回,請求不再進行下去
** ip_blacklist: Array, example: [`192.123.12.11`]
*/
module.exports = function(ip_blacklist) {
return async (ctx, next) => {
if(!Array.isArray(configs) && configs.length) {
let ip = ctx.request.headers[`x-real-ip`] || `` //獲取客戶端ip,由於使用nginx作為負載均衡,所以獲取ip的方式可通過x-real-ip欄位
if(ip && ip_blacklist.indexOf(ip) !== -1) {
await next()
} else {
return res.end(`ip restricted`)
}
} else {
await next()
}
}
}
複製程式碼
也請大家關注我的知乎專欄,漲漲粉:知乎專欄:前端思考