2

有没有办法将中间件添加到被调用以跟踪/ 响应是否已发送的快递app或链的末尾?routerres

我的意思是,无论是否:

  • 发送响应(字符串、JSON 等)
  • 静态服务文件。
  • 在静态文件夹中找不到文件。
  • 达到了一个全面的回调。
  • 到达错误中间件。

例子

例如,如果我想记录所有内容......

响应是否成功即:它通过express.static( ... )中间件提供文件、从数据库中获取的一些数据或自定义中间件,或者再次...如果它失败/抛出错误...,有没有办法在最后调用回调?

到目前为止,据我所知,按照设计,如果静态文件成功提供服务(通过express.static),它不会调用next(),因此链停在那里。

对于任何使用 的定制中间件res.send(),您通常不想在next()之后调用,因为它可能会导致一些不良副作用(重新发送标头的错误)。

对于错误处理程序来说,这更容易,因为所有不成功的响应都可以在这里捕获。

但是它如何输出成功/不成功的响应呢?这可能是没有中间件就应该完成的事情吗?

4

2 回答 2

3

我使用的解决方案最终与 @idbehold解决方案略有不同,但简而言之,在快速应用程序中间件链的最顶端,我必须将回调挂钩到Response 对象的事件,该事件在大多数情况下都会被触发(全部?)我需要跟踪成功服务的请求的 HTTP 状态代码。resfinish

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.
})
于 2019-04-24T05:04:35.470 回答
2

node.js 和 Express 的异步架构在执行此操作时存在概念上的困难。我将描述一般问题,然后讨论一些可能的解决方法。

首先,每个 Express 处理程序都可以是异步的。因此,它几乎立即被调用并返回,并且该世界之外的任何人都不知道它是否仍在等待某个异步操作完成,然后才最终发送其响应,或者它是否只是没有做任何事情。从字面上看,你无法从外面的世界中分辨出来。

其次,您可以监视给定的请求以查看它是否调用错误处理程序或是否发送响应。由于上述原因,无法监视请求处理程序以查看它是否未能发送任何内容 - 您无法知道它是否仍在等待某些异步事情完成。

所以,这是我能推荐的最好的:

  1. 钩子res.end()看它什么时候被调用。这表明响应现已完成(无论是错误还是成功)。您可以在Medet 在上述评论中链接的express-afterware模块中看到这样做的示例。一般的想法是,您将在覆盖链的早期位置拥有自己的中间件,res.end()以便您可以看到它何时被调用。早期的中间件只会安装覆盖并调用next()以继续处理程序链。然后,当响应完成时,您的覆盖会看到它res.end()被调用。这应该适用于发送响应的所有情况。

  2. 然后,您仍然需要处理没有发送响应的情况(这可能是由于代码错误,因为所有请求最终都应该得到响应)。我知道的唯一方法是为请求实现某种超时。您可以使用内置机制server.setTimeout(),也可以在中间件中实现自己的机制(与步骤 1 中描述的中间件相同)。然后,在您指定的某个超时之后,如果尚未发送响应,您将接管并发送一些错误响应。

  3. 在链的早期安装您自己的错误中间件,以查看并记录所有错误。请注意,它res.end()仍然会被调用,因此即使出现错误,步骤 1 中的行为仍然会被触发(错误响应仍然调用res.end())。

于 2019-04-23T21:21:41.227 回答