在 node.js / Express 为什么有时在 next() 之后需要返回语句,有时不需要?



在下面的测试代码中,检查req.query以查看其值是否为name=cat。 如果不是这样next()则会触发下一件中间件。 这是在next()后不包含return语句即可完成的,并且按预期工作。

app.get('/test', (req, res, next) => {
if (req.query.name != 'cat') {
next();
} 
res.send('it was cat');
});
app.get('/test', (req, res) => {
res.send('it was not cat');
});

但是,当我在第二个中间件中将res.send更改为res.sendFile时,行为完全不同。

app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});

更改后res.send('it was cat');在第一个中间件中每次都会触发,无论名称的值如何。 此外,第二个中间件永远不会触发。

这可以通过在第一个中间件中next()后添加一个return来轻松修复。 行为再次变得可预测。

app.get('/test', (req, res, next) => {
if (req.query.name != 'cat') {
next();
return;
} 
res.send('it was cat');
});
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});

为什么在有和没有return语句的情况下会发生这种情况? 当我使用res.sendFile时需要return,但当我使用res.send时不需要。 我确定我错过了一些明显的东西,但我不明白模式。

这是在next()后不包含return语句的情况下完成的,并且它按预期工作。

不,它看起来按预期工作,但事实并非如此。例如,如果您检索不带查询参数的/test,或者检索不等于name=cat的查询参数,Express 将记录错误:

Error: Can't set headers after they are sent.

我无法重现您的第二个示例;对我来说,它总是返回"它是猫"(在没有return的示例中(。

任何 Express 处理程序/中间件的共同规则是:它应该结束响应本身(通过调用res.endres.sendres.renderres.sendFile等(或使用next传递请求。在您的情况下,如果没有return,您正在同时执行这两项操作。实际上,其结果将是不确定的。

当您的侦听器执行res.send('it was not cat')请求的整个处理时,不会撞到蹦床。next()调用在res.send('it was not cat')完成之前永远不会完成。 因此,当到达send('it was the cat')的代码时,响应已经发送。

但是,当侦听器执行res.sendFile()响应的处理是异步的。 该文件必须读入内存,这是节点中的非阻塞 I/O。 该 I/O 的回调被放入事件队列中,然后继续处理。 因此,next()调用返回,然后执行send('it was the cat')。 所有这些都是在文件读入内存之前。 稍后,当读取文件时,代码会尽职尽责地尝试发送响应,但为时已晚。

最新更新