egg.js 中间件

avatar
前端开发工程师 @阿里巴巴

作者:ICBU 谦行

写在最前:欢迎来到阿里巴巴 ICBU 交互&端技术前端团队专栏,我们将与你分享优质的前端技术文章,欢迎关注&交流哟!

egg.js 基于 Koa 实现,其中间件机制和 Koa 一样基于洋葱模型

编写中间件

写一个打印请求耗时的中间件

app/middleware/cost.js

async function cost(ctx, next) {
  const now = Date.now();
  await next();
  ctx.set('X-Response-Time', `${Date.now() - now}ms`);
}

一般中间件都会有自己的配置,为了避免每次使用配置,egg.js 对中间件配置做了约定

  1. 中间件存放在 app/middleware/ 目录下

  2. 每个中间件需要使用一个方法包裹,并 export 出来,方法接收由框架传来的两个参数

  3. options:中间件的配置项,框架会把 app.config[middlwwareName] 传递进来

  4. app:当前的 application 实例

因此需要包装一下上面写的中间件

module.exports = (options, app) => {
  return async function cost(ctx, next) {
    const now = Date.now();
    await next();
    ctx.set('X-Response-Time', `${Date.now() - now}ms`);
  };
};

中间件可以添加配置,允许开发者自定义响应头

module.exports = options => {
  const header = options.header || 'X-Response-Time';

  return async function cost(ctx, next) {
    const now = Date.now();
    await next();
    ctx.set(header, `${Date.now() - now}ms`);
  };
};

使用中间件

中间件编写完成后还需要手动挂载使用,支持以下方式:

应用全局使用

如果希望中间件应用级生效,可以把中间件在 config 文件中开启

// config/config.${env}.js
config.middleware = ['cost'];
config.cost = {
  header: 'egg-cost',
};

这样所有请求都会应用 cost 中间件,在响应头中使用 egg-const 输出响应时间

部分 router 使用

如果希望中间件只对单条路由生效,可以在路由中配置

const cost = app.middleware.cost({ header: 'egg-cost' });
app.get('/', cost, 'home.index');

通过规则配置

如果只希望某些特定规则的路由生效,一个个配置又十分麻烦,可以使用规则匹配,无论是应用层加载的中间件还是框架自带中间件,都支持几个通用的配置项:

  • enable:控制中间件是否开启

  • match:设置只有符合某些规则的请求才会经过这个中间件

  • ignore:设置符合某些规则的请求不经过这个中间件

    // config/config.${env}.js config.middleware = ['cost']; config.cost = { enable: true, ignore: /^/api/, header: 'egg-cost', }

match 和 ignore 支持的参数都一样,只是作用完全相反,不允许同时配置。match 和 ignore 支持多种类型的配置方式

  1. 字符串:当参数为字符串类型时,配置的是一个 url 的路径前缀,所有以配置的字符串作为前缀的 url 都会匹配上,也可以直接使用字符串数组

  2. 正则:当参数为正则时,直接匹配满足正则验证的 url 的路径

  3. 函数:当参数为一个函数时,会将请求上下文传递给这个函数,最终取函数返回的结果(true/false)来判断是否匹配

    match(ctx) { // 只有 ios 设备才开启 const reg = /iphone|ipad|ipod/i; return reg.test(ctx.get('user-agent')); },

有关更多的 match 和 ignore 配置情况,详见 egg-path-matching

使用 koa 中间件

因为同样使用洋葱模型,koa 中间件可以通过简单包装轻松引入 egg.js。以 koa-compress 为例,在 Koa 中使用时:

const koa = require('koa');
const compress = require('koa-compress');

const app = koa();

const options = { threshold: 2048 };
app.use(compress(options));

在 egg.js 使用

app/middleware/compress.js

// koa-compress 暴露的接口(`(options) => middleware`)和框架对中间件要求一致
module.exports = require('koa-compress');

config/config.default.js

module.exports = {
  middleware: [ 'compress' ],
  compress: {
    threshold: 2048,
  },
};

❤️ 感谢你看到最后~

阿里巴巴国际站(ICBU,Alibaba.com)是全球最大的跨境贸易和服务平台。我们时刻有新的技术挑战,有足够有趣的挑战满足你所有的好奇心和求知欲,有国外知名合作团队(Google & OpenSky)。

如果你想来 ICBU 和我一起开发前端,欢迎发简历到邮箱 shudai.lyy@alibaba-inc.com ,我们将快速响应你的面试安排。:-)