【发布时间】:2016-03-19 12:33:26
【问题描述】:
我有一个 Node.js Express 服务器,我在其中发送响应,然后尝试对同一个请求实例进行更多处理。
如果我在发送标头后写入 res,我会收到错误 - 但是如果我在发送回相应响应的响应后使用 req 可读流会发生什么?
换句话说,在完成整个请求处理之前,如何使用 Node.server 发送 HTTP 响应?
other 换句话说,如果我已经发回了响应,我如何在已经发送响应之后“消费”请求 - 真的只是除了发送之外做任何事情的问题吗?回复一下?
现在,使用与已发送响应相对应的请求对象(流)似乎存在一些奇怪的错误..
让我举一些例子,用代码-
以下显示了我的服务器中的最后 3 个 Express 中间件处理程序。作为一个有趣的旁注 - 一旦为请求调用一个中间件处理程序,就不能重新调用它(看起来如此)。所以发生的情况是,当发送响应时,下面的第一个处理程序被调用。然后,另一个执行路径(使用 process.nextTick 或 setImmediate)调用 next(),然后调用后两个处理程序,这意味着我最终会在我的服务器上登录 404。
app.use(function (req, res, next) {
var r;
var timeRequired = (Date.now() - req.request_start) + 'ms';
console.log("Time required for request:", timeRequired);
if (r = req.lectalTemp) {
if (!req.lectalSent) {
req.lectalSent = true;
res.status(r.status).json({timeRequired: timeRequired, success: r.data});
}
else {
console.log('Headers sent already, but here is the data that would have been sent:', r);
}
}
else {
next();
}
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('404: Not Found - ' + req.method + ' ' + req.originalUrl);
err.status = 404;
next(err);
});
app.use(function (err, req, res, next) {
var timeRequired = (Date.now() - req.request_start) + 'ms';
if (app.get('env') === 'production') {
res.status(err.status || 500).json({
error: 'sorry the API experienced an error serving your priority request'
});
}
else {
console.error(colors.bgRed(err), '\n', err.stack);
if (!res.headersSent && !req.lectalSent) {
req.lectalSent = true;
res.status(err.status || 500).json({
error: {
timeRequired: timeRequired,
errMessage: err.message,
errStack: err.stack
}
});
}
}
});
【问题讨论】:
-
你是否意识到如果一个中间件处理一个响应,你不应该继续调用
next(),因为如果你继续调用next(),它最终会到达你的404处理程序认为没有任何反应?如果您需要其他中间件继续处理响应,还有其他方法可以解决这个问题,但是那些其他处理程序必须确保在您已经发送响应后它们不会写入响应。您可以在请求或响应上设置一个标志,以表明它已经发送了响应,其他人可以检查该标志。 -
是的,这就是我所做的。你可以继续调用东西并使用 req 流,但我认为在发送响应后使用 res 流可能是禁止的
-
仅供参考,我问的原因是,我做了一个简单的优化,我做了一个非常关键的数据库调用,然后是一个不太重要的数据库调用。我想在关键调用后返回响应,然后让服务器在响应发送后继续处理不太关键的数据库调用,这对我来说似乎很正常。
-
所以,我不明白你的问题是什么。发送响应后,只需交出 res 流即可。您可以根据需要继续在服务器上运行其他代码,并且可以从 req 对象中读取所有您想要的内容。您所说的错误发生在您在发送响应后尝试使用 res 对象时。
-
在发送响应后,您无法写入响应流。其他什么都可以。由于响应流上的大多数方法都是关于写入或准备写入的,因此您可能应该在发送响应后避免使用响应流。