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


Egg是基於koa的,因此Egg的中間件和Koa的中間件是類似的。都是基於洋蔥圈模型的。

在Egg中,比如我想禁用某些IP地址來訪問我們的網頁的時候,在egg.js中我們可以使用中間件來實現這個功能,中間件的作用無非就是說在Egg的外層在包一層來判斷某些事情是否符合要求,也就是在洋蔥圈模型外面再進行包一層。
在Egg入門二學習中(https://www.cnblogs.com/tugenhua0707/p/10226799.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. 因此整個項目的目錄變成如下這個樣子:

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

編寫中間件

我們在 app/middleware 目錄中 新建一個 forbidIp.js 文件,該文件的作用是 禁用某些ip地址訪問我們的網頁。因此代碼編寫如下:

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 中加入下面的配置就可以完成了中間件的開啟和配置:代碼如下:

// 配置需要的中間件,數組的順序即為中間件加載的順序
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配置了。

如上中間件代碼,它接收兩個參數:options 和 app;
options參數指的是 app.config[${middlewareName}]傳進來。我們在 如上中間件代碼中打印 options; console.log(options); 及 打印 console.log(app); 如下圖所示:

可以看到 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源碼中中間件代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM