Egg入門學習(三)---理解中間件做用

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)

查看github源碼中中間件代碼

相關文章
相關標籤/搜索