2022-10-06 10:29:53 +08:00
|
|
|
|
# 中间件
|
2022-09-29 21:05:31 +08:00
|
|
|
|
|
|
|
|
|
## 添加方法
|
|
|
|
|
|
|
|
|
|
1. `app.acl.use()` 添加资源权限级中间件,在权限判断之前执行
|
|
|
|
|
2. `app.resourcer.use()` 添加资源级中间件,只有请求已定义的 resource 时才执行
|
|
|
|
|
3. `app.use()` 添加应用级中间件,每次请求都执行
|
|
|
|
|
|
|
|
|
|
## 洋葱圈模型
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
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 查看,浏览器响应的数据是:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{"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()` 添加的其他中间件
|
|
|
|
|
|
|
|
|
|
也可以使用 `before` 或 `after` 将中间件插入到前面的某个 `tag` 标记的位置,如:
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
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 添加的。
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
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 查看,浏览器响应的数据是:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{"data": [1,2]}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
访问 http://localhost:13000/api/test:list 查看,浏览器响应的数据是:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{"data": [5,3,7,1,2,8,4,6]}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### resource 未定义,不执行 resourcer.use() 添加的中间件
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
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 查看,浏览器响应的数据是:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{"data": [1,2]}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
以上示例,hello 资源未定义,不会进入 resourcer,所以就不会执行 resourcer 里的中间件
|
|
|
|
|
|
|
|
|
|
## 中间件用途
|
|
|
|
|
|
|
|
|
|
待补充
|
|
|
|
|
|
|
|
|
|
## 完整示例
|
|
|
|
|
|
|
|
|
|
待补充
|
|
|
|
|
|
2022-09-30 12:40:32 +08:00
|
|
|
|
- [samples/ratelimit](https://github.com/nocobase/nocobase/blob/main/packages/samples/ratelimit/) IP rate-limiting
|