是否有办法将中间件添加到快速app
或router
链的末尾,该链被调用以跟踪是否发送了res
/响应?
我的意思是,无论是否:
例如,如果我想记录所有内容......
响应是否成功,即:它通过express.static( ... )
中间件提供文件,从数据库提取的一些数据,或自定义中间件,或者再次......如果它失败/抛出错误......,是否有在最后调用回调的方法?
到目前为止,我可以理解,似乎,按照设计,如果静态文件成功提供(通过express.static),它不会调用next()
,所以链停在那里。
对于使用res.send()
的任何定制中间件,您通常不希望之后调用next()
,因为它可能会导致一些不良副作用(标题重新发送错误)。
对于错误处理程序,这更容易,因为可以在此处捕获所有不成功的响应。
但它如何输出成功/不成功的回复?这可能是没有中间件的事情吗?
对于这样做,node.js和Express的异步架构存在概念上的困难。我将描述一般问题,然后讨论一些可能的解决方法。
首先,每个Express处理程序都可以是异步的。因此,它被调用并立即返回,并且该世界之外的任何人都不知道在最终发送响应之前它是否还在等待某些异步操作完成,或者它是否只是没有做任何事情。从字面上看,你无法从外界了解到。
其次,您可以监视给定的请求,以查看它是调用错误处理程序还是发送响应。由于上述原因,无法监视请求处理程序以查看它是否发送了任何内容 - 您无法知道它是否仍在等待某些异步操作完成。
所以,这是我能推荐的最好的:
res.end()
看它何时被召唤。这表明现在已完成响应(无论是错误还是成功)。您可以在mezt链接到上述评论的express-afterware模块中看到这样做的示例。一般的想法是你在链中很早就有自己的中间件覆盖res.end()
所以你可以看到它被调用的时间。早期的中间件只会安装覆盖并调用next()
来继续处理程序链。然后,当响应完成时,你的覆盖将看到res.end()
被调用。这适用于发送响应的所有情况。server.setTimeout()
,也可以在中间件中实现自己的(与步骤1中描述的相同的中间件)。然后,在您指定的某个超时之后,如果尚未发送任何响应,您将接管并发送一些错误响应。res.end()
,因此即使出现错误,仍会触发步骤1中的行为(错误响应仍然会调用res.end()
)。我使用的解决方案最终与@idbehold的this one略有不同,但简而言之,在Express app中间件链的最顶层,我不得不挂钩回调res
Response对象的finish
事件,该事件被大多数触发(全部?)HTTP状态代码我需要跟踪成功提供的请求。
app.use( ( req, res, next ) => {
res.on( 'finish', () => {
var codeStr = String( res.statusCode );
codeStr = codeStr[res.statusCode < 400 ? 'green' : 'red'];
var output = [req.method.green, req.fullUrl().green, codeStr];
trace( output.join( ' ' ) );
} );
next();
});
我现在可以得到这样的东西:
好的!因此,如果您的中间件链的“末端”还有一个错误处理程序,该错误处理程序提供错误的404
代码,它将触发finish
对象上的res
事件。
这种错误处理程序的示例:
app.use( ( err, req, res, next ) => {
trace( "Error!".red );
trace( err );
res.status( 404 ).send(); // Triggers 'finish' on res.
})