NodeJS 如何在链的末端添加快速中间件,无论发生什么情况(OK/FAIL响应),中间件都会被调用?

3htmauhk  于 2022-12-22  发布在  Node.js
关注(0)|答案(3)|浏览(119)

有没有办法在快速approuter链的末尾添加中间件,调用该中间件来跟踪res/响应是否已发送?
我是说,不管是不是:

  • 发送响应(字符串、JSON等)
  • 静态服务文件。
  • 在静态文件夹中未找到文件。
  • 已达到"捕获所有"回调。
  • 到达中间件时出错。

示例

例如,如果我想记录所有内容...
响应是否成功,* 即:它通过express.static( ... )中间件提供文件,从数据库或自定义中间件获取一些数据,或者再次......如果它失败/抛出错误...... *,是否有办法在最后调用回调?
到目前为止,我所能理解的似乎是,按照设计,如果一个静态文件成功地得到服务(通过express.static),它不会调用next(),因此链就到此为止。
对于任何使用res.send()的定制中间件,您通常不希望在之后调用next(),因为这可能会导致一些不希望的副作用(重新发送带有标头的错误)。
对于错误处理程序来说,这更容易,因为所有不成功的响应都可以在这里捕获。
但是它怎么能同时输出成功/不成功的响应呢?这是不需要中间件就能完成的事情吗?

0yycz8jy

0yycz8jy1#

我采用的解决方案与this one的区别在于**@idlook**,但简单地说,在Express应用中间件链的最顶端,我必须将回调挂接到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代码,这将触发res对象上的finish事件。
此类错误处理程序的示例:

app.use( ( err, req, res, next ) => {
    trace( "Error!".red );
    trace( err );

    res.status( 404 ).send(); // Triggers 'finish' on res.
})
sirbozc5

sirbozc52#

在node.js和Express的异步体系结构中,要做到这一点有一个概念上的困难,我将描述这个一般性问题,然后讨论一些可能的解决方法。
首先,每个Express处理程序都可以是异步的。因此,它被调用并几乎立即返回,外界没有人知道它是否仍在等待某个异步操作完成,然后才最终发送其响应,或者它只是没有做任何事情。从外界看,你根本无法判断。
第二,你可以监视一个给定的请求,看看它是否调用了一个错误处理程序,或者是否发送了一个响应。没有办法监视一个请求处理程序,看看它是否因为上述原因而发送失败--你没有办法知道它是否还在等待某个异步的事情完成。
所以,这里是我能推荐的最好的:
1.挂接res.end()以查看何时调用它。(无论是错误还是成功)。你可以在Medet在上面的评论中链接的express-afterware模块中看到这样做的一个例子。一般的想法是,你会在链的早期有自己的中间件来覆盖res.end(),这样你就可以看到它何时被调用。早期的中间件只需要安装覆盖并调用next()来继续处理程序链,然后,当响应完成时,覆盖将看到res.end()被调用,这应该适用于所有发送响应的情况。
1.然后,您仍然需要处理没有发送响应的情况(这可能是由于错误的代码,因为所有的请求最终都应该得到响应)我所知道的唯一方法是为请求实现某种类型的超时,您可以使用内置机制server.setTimeout(),也可以在中间件中实现自己的机制(与步骤1中描述的相同的中间件)。然后,在您指定的某个超时之后,如果还没有发送响应,您将接管并发送一些错误响应。
1.在链的早期安装您自己的错误中间件,它将查看并记录所有错误。注意,仍然会调用res.end(),因此即使出现错误,步骤1中的行为仍然会被触发(错误响应仍然会调用res.end())。

zzzyeukh

zzzyeukh3#

可以使用响应对象的finish事件在请求结束时触发一段代码。finish事件在响应发送到客户端并且所有数据都刷新到网络时发出。

app.use(function(req, res, next) {
  res.on('finish', function() {
    console.log('Request finished');
  });
  next();
});

相关问题