初用Nodejs koa,为啥同一个中间件里的代码会执行两次?
初用Nodejs koa,为啥同一个中间件里的代码会执行两次?
代码如下: var app = require(‘koa’)();
var i = 0;
app.use(function *(next) {
yield next;
console.info(i++);
});
app.use(function *(next) {
yield next;
this.body = 'Hello, total is ' + i;
});
app.listen(3000);
就这样的代码,每次我刷新页面,控制台的i总是+2,为啥不是+1?页面上的i也是+2,很奇怪。。。哪里的问题呢?
favicon?
app.use(function *(next) {
console.log(this.url); // 加上这个观察下, 到底收到了几个请求
yield next;
console.info(i++);
});
这个问题可以通过分析 Koa 中间件的调用机制来理解。Koa 使用了中间件栈(middleware stack)的概念,每个中间件都会按顺序依次执行,并且通常每个中间件都需要调用 yield next
来确保后续中间件能够被执行。这种设计使得请求在进入和离开中间件时可以进行一些处理。
在你的例子中,有两个中间件被注册到应用中。当一个请求到达时,第一个中间件会被执行,然后它调用 yield next
来执行下一个中间件。第二个中间件执行完毕后,控制权返回到第一个中间件,此时 yield next
之后的代码会被执行。
由于你在这个中间件里使用了一个全局变量 i
来计数,这个变量会在每次请求时被重置为初始值 0
。然而,由于 Koa 的中间件机制,每次请求时,这个中间件实际上会被执行两次:一次是在进入时,另一次是在返回时。因此,每次请求时,i
会被累加两次,导致你看到的结果是每次请求时 i
都增加了 2。
为了更好地理解这一点,我们可以修改一下代码,使其更加清晰地展示中间件的执行过程:
var Koa = require('koa');
var app = new Koa();
var i = 0;
app.use(async (ctx, next) => {
console.log(`Before middleware: ${i}`);
await next();
console.log(`After middleware: ${i}`);
i++;
});
app.use(async ctx => {
ctx.body = 'Hello, total is ' + i;
});
app.listen(3000);
在这个修改后的代码中,我们添加了一些日志输出,以便更清楚地看到中间件的执行过程。每次请求时,你会看到类似如下的输出:
Before middleware: 0
After middleware: 0
Before middleware: 1
After middleware: 1
这说明每次请求时,中间件确实被调用了两次。第一次调用是在请求进入时,第二次调用是在请求返回时。
如果你希望 i
只增加一次,可以将 i
定义为一个闭包内的局部变量,或者使用其他方式确保其只在特定条件下增加。
请求了 favicon
有可能是favicon 但我有时候重启服务 又只+1而不是+2 看起来没规律一样
当你使用 Koa 框架时,中间件是以栈的形式依次调用的。你提供的代码中,每个中间件都会调用 yield next;
,这会导致中间件栈中的下一个中间件被执行。由于你的两个中间件都包含了 yield next;
,这就导致了每个请求经过这两个中间件时会被执行两次。
具体来说,当你刷新页面时,请求会进入第一个中间件,执行 console.info(i++);
,此时 i
变为 1;然后它会调用 yield next;
,导致进入第二个中间件,最后回到第一个中间件完成执行。因此,当请求完全处理完毕后,i
增加了两次。
下面是修改后的代码,你可以看到 i
只会增加一次:
var Koa = require('koa');
var app = new Koa();
let i = 0;
// 第一个中间件
app.use(async (ctx, next) => {
i++;
console.info(i);
await next();
});
// 第二个中间件
app.use(async (ctx, next) => {
ctx.body = 'Hello, total is ' + i;
});
app.listen(3000);
这样,每次刷新页面时,i
只会增加一次,并且页面显示的 total
值也会正确地反映当前的 i
值。