nocobase/docs/en-US/development/server/middleware.md
2022-11-06 13:48:06 +08:00

161 lines
3.6 KiB
Markdown

# Middleware
## How to register middleware?
The registration method for middleware is usually written in the load method
```ts
export class MyPlugin extends Plugin {
load() {
this.app.acl.use();
this.app.resourcer.use();
this.app.use();
}
}
```
Notes.
1. `app.acl.use()` Add a resource-permission-level middleware to be executed before permission determination
2. `app.resourcer.use()` Adds a resource-level middleware that is executed only when a defined resource is requested
3. `app.use()` Add an application-level middleware to be executed on every request
## Onion Circle Model
```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);
});
```
Visit http://localhost:13000/api/hello to see that the browser responds with the following data
```js
{"data": [1,3,4,2]}
```
## Built-in middlewares and execution order
1. `cors`
2. `bodyParser`
3. `i18n`
4. `dataWrapping`
5. `db2resource` 6.
6. `restApi` 1.
1. `parseToken` 2.
2. `checkRole`
3. `acl` 1.
1. `acl.use()` Additional middleware added
4. `resourcer.use()` Additional middleware added
5. `action handler`
7. `app.use()` Additional middleware added
You can also use `before` or `after` to insert the middleware into the location of one of the preceding `tag`, e.g.
```ts
app.use(m1, { tag: 'restApi' });
app.resourcer.use(m2, { tag: 'parseToken' });
app.resourcer.use(m3, { tag: 'checkRole' });
// m4 will come before m1
app.use(m4, { before: 'restApi' });
// m5 will be inserted between m2 and m3
app.resourcer.use(m5, { after: 'parseToken', before: 'checkRole' });
```
If no location is specifically specified, the order of execution of the added middlewares is
1. middlewares added by `acl.use` will be executed first
2. then the ones added by `resourcer.use`, including the middleware handler and action handler
3. and finally the ones added by `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);
},
},
});
```
Visit http://localhost:13000/api/hello to see that the browser responds with the data
```js
{"data": [1,2]}
```
Visiting http://localhost:13000/api/test:list to see, the browser responds with the following data
```js
{"data": [5,3,7,1,2,8,4,6]}
```
### Resource undefined, middlewares added by resourcer.use() will not be executed
```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);
});
```
Visit http://localhost:13000/api/hello to see that the browser responds with the following data
```js
{"data": [1,2]}
```
In the above example, the hello resource is not defined and will not enter the resourcer, so the middleware in the resourcer will not be executed
## Middleware Usage
TODO
## Example
- [samples/ratelimit](https://github.com/nocobase/nocobase/blob/main/packages/samples/ratelimit/) IP rate-limiting