nocobase/docs/zh-CN/development/server/middleware.md
2022-11-06 13:48:09 +08:00

3.3 KiB
Raw Permalink Blame History

中间件

如何注册中间件?

中间件的注册方法一般写在 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:13000/api/hello 查看,浏览器响应的数据是:

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

内置中间件及执行顺序

  1. cors
  2. bodyParser
  3. i18n
  4. dataWrapping
  5. db2resource
  6. restApi
    1. parseToken
    2. checkRole
    3. acl
      1. acl.use() 添加的其他中间件
    4. resourcer.use() 添加的其他中间件
    5. 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 添加的。
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);
});

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

app.resourcer.define({
  name: 'test',
  actions: {
    async list(ctx, next) {
      ctx.body = ctx.body || [];
      ctx.body.push(7);
      await next();
      ctx.body.push(8);
    },
  },
});

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

{"data": [1,2]}

访问 http://localhost:13000/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:13000/api/hello 查看,浏览器响应的数据是:

{"data": [1,2]}

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

中间件用途

待补充

示例