中间件

如何注册中间件?

中间件的注册方法一般写在 load 方法里

export class MyPlugin extends Plugin {
  load() {
    this.app.acl.use();
    this.app.resourcer.use();
    this.app.use();
  }
}

说明:

  1. app.acl.use() 添加资源权限级中间件,在权限判断之前执行
  2. app.resourcer.use() 添加资源级中间件,只有请求已定义的 resource 时才执行
  3. app.use() 添加应用级中间件,每次请求都执行

洋葱模型

app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(1);
  await next();
  ctx.body.push(2);
});

app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(3);
  await next();
  ctx.body.push(4);
});

访问 http://localhost:3000/api/hello 查看,浏览器响应的数据是:

{"data": [1,3,4,2]}

内置中间件及执行顺序

  1. bodyParser
  2. cors
  3. i18n
  4. dataWrapping
  5. db2resource
  6. restApi 其实就是resourcer
    1. auth
    2. acl
      1. acl.use() 添加的其他中间件
    3. resourcer.use() 添加的其他中间件
    4. action handler
  7. app.use() 添加的其他中间件

也可以使用 beforeafter 将中间件插入到前面的某个 tag 标记的位置,如:

app.use(m1, { tag: 'restApi' });
app.resourcer.use(m2, { tag: 'parseToken' });
app.resourcer.use(m3, { tag: 'checkRole' });
// m4 将排在 m1 前面
app.use(m4, { before: 'restApi' });
// m5 会插入到 m2 和 m3 之间
app.resourcer.use(m5, { after: 'parseToken', before: 'checkRole' });

如果未特殊指定位置,新增的中间件的执行顺序是:

  1. 优先执行 acl.use 添加的,
  2. 然后是 resourcer.use 添加的,包括 middleware handler 和 action handler,
  3. 最后是 app.use 添加的。

访问 http://localhost:3000/api/hello 查看,浏览器响应的数据是:

{"data": [1,2]}

访问 http://localhost:3000/api/test:list 查看,浏览器响应的数据是:

{"data": [5,3,7,1,2,8,4,6]}

resource 未定义,不执行 resourcer.use() 添加的中间件

app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(1);
  await next();
  ctx.body.push(2);
});

app.resourcer.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(3);
  await next();
  ctx.body.push(4);
});

访问 http://localhost:3000/api/hello 查看,浏览器响应的数据是:

{"data": [1,2]}

以上示例,hello 资源未定义,不会进入 resourcer,所以就不会执行 resourcer 里的中间件

辅助插件

开启开发工具,可以查看当前请求的中间件执行顺序和相关use的堆栈地址

Middleware Execution Flow