Egg.js基础入门三:中间件与定时任务

续接上篇~~~

中间件

egg中间件与koa一致保持洋葱模型

按照约定中间件必须位于/app/middleware目录下

全局使用中间件

定义一个全局中间件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// /app/middleware/counter.js
'use strict'
// 中间件必须接受一个options参数
module.exports = options => {
// 返回一个异步函数,异步函数接收两个参数,与koa一致分别是ctx和next
return async (ctx, next) => {
if(ctx.session.counter){
ctx.session.counter ++
} else {
ctx.session.counter = 1
}
// 需要next才能向下运行,await等待后续代码运行
// 中间件使用洋葱模型,
// next之前的代码第一次进入时运行,next之后的代码会在第二次进入后运行
await next()
}
}

中间件想要在区局使用必须在config中进行一些配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// /config/config.default.js
'use strict';

module.exports = appInfo => {

const config = exports = {};

// 如果想要全局使用中间件需要在此进行配置
// 我们按照约定将中间价写入到/app/middleware目录下
// 所以在此处配置中写入中间件的文件名即可加载中间件到全局使用
config.middleware = ['counter'];

return {
...config
};
};


指定路由使用中间件

可以将中间件应用于指定路由:

  • 在config中取消对于中间件的全局配置
  • 在router中取出中间件并将其配置到指定路由中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// /config/config.default.js

'use strict';

module.exports = appInfo => {

const config = exports = {};

// 中间件仅用于指定路由,不能在这里配置
config.middleware = [];

return {
...config
};
};
1
2
3
4
5
6
7
8
9
10
11
12
// /app/router.js
'use strict';

module.exports = app => {
// 取出中间件
const counter = app.middleware.counter()
const { router, controller } = app;
// 指定中间件仅在该路由使用,在路由中作为第二个参数传入
router.get('/mid4path', counter, controller.demo.useMiddleWare)
};


中间件的执行顺序

前边说过Egg中的中间件是严格遵守洋葱模型的,可以看如下示例:

假设有如下路由:

1
2
3
4
5
6
7
8
// /app/router.js
'use strict';

module.exports = app => {
const { router, controller } = app;
router.get('/testMiddleWare', controller.home.testMiddleWare)
};

控制器代码如下:

1
2
3
4
5
6
// /app/controller/home.js
async testMiddleWare(){
const ctx = this.ctx
console.log('控制器')
ctx.body = 'success'
}

编写两个中间件并在config中进行配置:

1
2
3
4
5
6
7
8
9
10
// /app/middleware/demo.js
'use strict'

module.exports = options => {
return async (ctx, next) => {
console.log('一号中间件1')
await next()
console.log('一号中间件2')
}
}
1
2
3
4
5
6
7
8
9
10
// /app/middleware/test.js
'use strict'

module.exports = options => {
return async (ctx, next) => {
console.log('二号中间件1')
await next()
console.log('二号中间件2')
}
}
1
2
// /config/config.default.js
config.middleware = ['demo', 'test'];

从代码可以看出我们定义了两个中间件,在next前后分别进行了输出来演示洋葱模型的效果。

在config中我们定义中间件的顺序为demo在前。test在后。

所以我们访问路由应该会依次访问 demo -> test -> controller -> test -> demo

事实上控制台确实会依次打印如下内容:

1
2
3
4
5
一号中间件1
二号中间件1
控制器
二号中间件2
一号中间件2

定时任务

定时任务必须放到/app/schedule目录下

定时任务的方式与Controller类似,但是类中的方法命名也有具体要求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// /app/schedule/get_time.js
'use strict'
// 必须引入Subscription
const Subscription = require('egg').Subscription

// 定义一个类继承自Subscription
class GetTime extends Subscription {
// 静态方法声明任务的一些属性,需要使用get关键字
// 必须叫schedule,要返回一个对象包含任务的属性配置
static get schedule(){
// 返回一个对象
return {
// 任务间隔时间
// 除了用interval之外,也可以使用cron,输入cron表达式,不用传年份
// cron: '* * * * * *'
interval: '10s',
// 任务的类型: worker / all
type: 'worker'
}
}
// 任务的内容,是一个异步方法,命名为subscribe
async subscribe(){
console.log('run schedule')
}
}

// 暴露
module.exports = GetTime

我们如上定义好一个定时任务之后,不需要做额外的配置,只要启动程序,定时任务就会启动。

作者

胡兆磊

发布于

2022-04-01

更新于

2022-10-23

许可协议