Egg是基於koa的,所以Egg的中間件和Koa的中間件是相似的。都是基於洋蔥圈模型的。css
在Egg中,好比我想禁用某些IP地址來訪問咱們的網頁的時候,在egg.js中咱們可使用中間件來實現這個功能,中間件的做用無非就是說在Egg的外層在包一層來判斷某些事情是否符合要求,也就是在洋蔥圈模型外面再進行包一層。
在Egg入門二學習中(https://www.cnblogs.com/tugenhua0707/p/10226799.html), 咱們最後的項目的目錄結構以下:html
egg-demo2 ├── app │ ├── controller │ │ └── home.js | | |-- index.js │ └── router.js │ ├──public | | |---css | | | |-- index.css | | |---js | | | |-- index.js | |--- view | | |-- index | | | |-- list.tpl(模板文件list) | |--- service | | |--- index.js ├── config │ └── config.default.js └── package.json
在Egg中,中間件也有本身的配置和目錄,所以在Egg中約定了中間件是放在 app/middleware 目錄中的文件。該文件須要exports一個普通的function. 所以整個項目的目錄變成以下這個樣子:git
egg-demo2 ├── app │ ├── controller # 用於解析用戶的輸入,處理後返回響應的結果 │ │ └── home.js | | |-- index.js │ └── router.js # 用於配置url路由的配置規則 │ ├──public # 資源文件目錄 | | |---css | | | |-- index.css | | |---js | | | |-- index.js | |--- view # 存放模板文件的目錄 | | |-- index | | | |-- list.tpl(模板文件list) | |--- service # 編寫業務邏輯的目錄 | | |--- index.js | |--- middleware # 用於編寫中間件的目錄 | | |--- xxx.js ├── config # 相關的配置文件 │ └── config.default.js └── package.json
編寫中間件github
咱們在 app/middleware 目錄中 新建一個 forbidIp.js 文件,該文件的做用是 禁用某些ip地址訪問咱們的網頁。所以代碼編寫以下:json
module.exports = (options, app) => { return async function forbidIp(ctx, next) { console.log(options); console.log('---------'); console.log(app); // 須要被屏蔽的id const ids = options.forbidips; // 獲取客戶端的ip const clientIp = ctx.request.ip; const isHasIp = ids.some(val => { if (val === clientIp) { return true; } return false; }); if (isHasIp) { ctx.status = 403; ctx.body = '您的IP已經被屏蔽掉了'; } else { await next(); } } }
使用中間件數組
如上中間件編寫完成後,咱們還須要手動掛載中間件。所以咱們須要在 config/config.default.js 中加入下面的配置就能夠完成了中間件的開啓和配置:代碼以下:app
// 配置須要的中間件,數組的順序即爲中間件加載的順序 exports.middleware = [ 'forbidIp' ]; // 上面中間件的配置 ip exports.forbidIp = { forbidips: [ '192.168.1.12', '127.0.0.1', ] }
注意:如上 exports.middleware = ['forbidIp']; 該 forbidIp 指向與 app/middleware 中的 forbidIp.js, 所以須要注意大小寫。也就是說是 forbidIp.js 中間件。而後下面的 exports.forbidIp = {}; forbidIp中間件的名字也須要同樣的。exports.forbidIp 裏面的對象就是中間件的ip配置了。koa
如上中間件代碼,它接收兩個參數:options 和 app;
options參數指的是 app.config[${middlewareName}]傳進來。咱們在 如上中間件代碼中打印 options; console.log(options); 及 打印 console.log(app); 以下圖所示:async
能夠看到 console.log(options); options參數的值就是 config配置項中的 學習
{ forbidips: [ '192.168.1.12', '127.0.0.1', ] }
打印 config.log(app) 的值,如上圖所示;它的含義是指 當前應用Application的實列。
所以咱們繼續訪問 http://127.0.0.1:7001/ 後能夠看到以下信息,頁面被禁用了。以下圖所示:
若是咱們繼續把 config/config.default.js 配置代碼改爲其餘的ip地址,代碼以下:
// 配置須要的中間件,數組的順序即爲中間件加載的順序 exports.middleware = [ 'forbidIp' ]; // 上面中間件的配置 ip exports.forbidIp = { forbidips: [ '192.168.1.12', '127.0.0.12' ] }
咱們繼續訪問 http://127.0.0.1:7001/ 後,頁面就正常了。以下所示:
二:在 router.js路由中使用中間件。
如上使用中間件都是全局的,每一次請求都會處理的,可是有時候我想針對單個路由生校的話,咱們就不須要再 config中配置了。咱們直接在路由中配置便可。
router.js在未使用中間件處理以前代碼是以下:
module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.get('/index', controller.index.list); }
如今咱們須要在 router.get('/'); 下使用禁用ip中間件,所以咱們能夠先註釋掉 config中全局的中間件配置。咱們能夠直接在 router.js 下處理便可,以下代碼所示:
首先:config/config.default.js 代碼註釋掉中間件:
/* // 配置須要的中間件,數組的順序即爲中間件加載的順序 exports.middleware = [ 'forbidIp' ]; // 上面中間件的配置 ip exports.forbidIp = { forbidips: [ '192.168.1.12', '127.0.0.12' ] } */
而後在單個路由中使用中間件, router.js的代碼以下:
module.exports = app => { const { router, controller } = app; // 路由中使用中間件 const forbidIp = app.middleware.forbidIp({ forbidips: [ '127.0.0.1' ] }); router.get('/', forbidIp, controller.home.index); router.get('/index', controller.index.list); }
而後咱們繼續訪問 http://127.0.0.1:7001/ 後,頁面也會提示該ip地址已經被屏蔽掉了。
更多的關於中間件配置介紹,請看官網中介紹的(https://eggjs.org/zh-cn/basics/middleware.html)