中间件

koa中的中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
// console.log(ctx); 上下文
console.log('first');
next(); // 调用下一个中间件
})

app.use((ctx, next) => {
console.log('second');
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

执行下面的代码,然后在浏览器中输入127.0.0.1:3000,终端依次打印出 first second

洋葱模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
console.log(1);
next();
console.log(2)
})

app.use((ctx, next) => {
console.log(3);
next();
console.log(4);
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

执行上面的代码,然后在浏览器中输入127.0.0.1:3000,终端会依次打印出 1 3 4 2

next返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
console.log(1);
const a = next();
console.log(a);
console.log(2);
})

app.use((ctx, next) => {
console.log(3);
console.log(4);
return "abc";
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

执行上面的代码,然后在浏览器中输入127.0.0.1:3000,终端会依次打印 1 3 4 Promise { 'abc' } 2,如果没有 return "abc";,那么 a 为 Promise { undefined },可以看到,next() 的返回值就是 Promise

await async

求值

加上 awaitasync 确保按洋葱顺序执行,如果不加上,很难保证按洋葱顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const Koa = require('koa');

const app = new Koa();

app.use(async (ctx, next) => {
console.log(1);
const a = await next(); // 进行求值得到 'abc'
console.log(a);
console.log(2);
})

app.use((ctx, next) => {
console.log(3);
console.log(4);
return "abc";
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

执行上面的代码,然后在浏览器中输入127.0.0.1:3000,终端会依次打印 1 3 4 abc 2

如果使用 .then,那么结果就不一样了,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const Koa = require('koa');

const app = new Koa();

app.use(async (ctx, next) => {
console.log(1);
const a = next();
a.then((res) => {
console.log(res);
})
console.log(2);
})

app.use((ctx, next) => {
console.log(3);
console.log(4);
return "abc";
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

执行上面的代码,在浏览器中输入127.0.0.1:3000,终端会依次打印 1 3 4 2 abc

阻塞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
const axios = require('axios');
const start = Date.now();
const res = axios.get(`https://www.baidu.com`);
const end = Date.now();
console.log(end-start); // 0
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Koa = require('koa');

const app = new Koa();

app.use(async (ctx, next) => {
const axios = require('axios');
const start = Date.now();
const res = await axios.get(`https://www.baidu.com`);
const end = Date.now();
console.log(end-start); // 79
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

比较上面的代码,第二段代码把异步变成了同步,所以 end-start 会变得很大

ctx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const Koa = require('koa');

const app = new Koa();

app.use(async (ctx, next) => {
await next();
// 按照洋葱模型才能保证 r 是有值的,如果不加 await async,那么不一定是按照洋葱模型来执行
const r = ctx.r;
console.log(r);
})

app.use(async (ctx, next) => {
const axios = require('axios');
const res = await axios.get("https://www.baidu.com");
ctx.r = res;
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`)
})

express中的中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const express = require('express');

const app = express();

app.use((req, res, next) => {
console.log('1');
next();
})

app.use((req, res, next) => {
console.log('2');
next();
})

app.use((req, res, next) => {
console.log('3');
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`);
})

执行上面的代码,然后在浏览器中输入127.0.0.1:3000,终端会依次打印出 1 2 3

分类

应用级中间件
路由级中间件
错误处理中间件
内置中间件
第三方中间件

举例

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
const express = require('express');

const app = express();

app.use((req, res, next) => {
console.log('1');
next();
})

app.use('/a', (req, res, next) => {
console.log('2');
next();
})

app.get('/a', (req, res, next) => {
console.log('a');
})

app.use('/b', (req, res, next) => {
console.log('3');
})

app.listen(3000, () => {
console.log(`127.0.0.1:3000`);
})

上面这段代码,在浏览器中输入 http://127.0.0.1:3000 只会打印出 1,输入 http://127.0.0.1:3000/a 会依次打印出 1 2 a,输入 http://127.0.0.1:3000/b 回依次打印出 1 3。