【问题标题】:How do I capture a "response end" event in node.js+express?如何在 node.js+express 中捕获“响应结束”事件?
【发布时间】:2012-06-21 11:59:00
【问题描述】:

我想编写一个快速中间件函数,它在响应的“结束”事件(如果存在)上设置一个侦听器。目的是根据最终处理程序决定发送的 http 响应代码进行清理,例如记录数据库事务的响应代码和回滚/提交。即,我希望此清理对最终调用者透明。

我想在 express 中执行以下操作:

路由中间件

function (req, res, next) {
   res.on ('end', function () {
      // log the response code and handle db
      if (res.statusCode < 400) { db.commit() } else { db.rollback() }
   });
   next();
}

路线:

app.post ("/something", function (req, res) { 
    db.doSomething (function () {
       if (some problem) {
          res.send (500);
       } else {
          res.send (200);
       }
    });
 }

当我尝试这个时,'end' 事件处理程序永远不会被调用。 res.on('close') 也是如此,我在另一篇文章中读到过。此类事件会被触发吗?

我能想到的唯一其他方法是在自定义中间件中用我自己的版本包装 res.endres.send。这并不理想,因为res.endres.send 不接受回调,所以我不能只包装它们,调用原始代码,然后根据他们给我回电时设置的响应代码做我的事情(因为他们不会给我回电话)。

有没有简单的方法来做到这一点?

【问题讨论】:

  • 你为什么不在res.end之前做家务?
  • 这也很好,但我想把它作为中间件来做,也就是说,最终处理程序不必担心清理。因此,如果我想记录生成的响应代码,或者根据响应代码回滚/提交数据库事务,我希望它对最终处理程序透明地操作。所以我试图在调用 res.send 的结束处理程序和正在完成的请求之间的某个时刻捕获执行。
  • 但是正在定义状态码:/
  • 我是?我正在编写一个路由中间件函数。结束处理程序定义返回码。我想做一些事情来回应他们决定发送的内容。

标签: events node.js express response


【解决方案1】:

奇怪的是,当响应关闭时,响应似乎会发出一个“完成”事件: https://web.archive.org/web/20120825112648/http://sambro.is-super-awesome.com/2011/06/27/listening-for-end-of-response-with-nodeexpress-js/

尽管这个博客条目有点旧,但这个事件仍然存在 (Line 836 in lib/http.js),所以我认为它不会很快消失,即使节点和 express 的文档都没有提到它。 到 2014 年初,它已移至 line 504 on of lib/_http_outgoing.js 并且仍然有效。

顺便说一句,服务器响应上的“错误”事件可能不是您通常希望看到的。

【讨论】:

  • +1 我找不到文档,但当前的源代码(截至今天)仍然引发了事件。谢谢!
  • 无法使用完成或结束或关闭。有什么建议吗?
  • res.on ('header',func) FTW!
  • 这是记录在案的“完成”事件吗? :nodejs.org/api/http.html#http_event_finish
  • Express.js 响应扩展了内置的 http 响应,并且完成事件不是 express 特定的,因此它不在 express 文档中
【解决方案2】:

为了进一步@Amatsuyu 的回应,它应该是这样的:

res.on('finish', function() {
  // do stuff here
});

【讨论】:

  • 有没有办法在回调中访问 res 的最终状态?例如,回调是否可以查看 res 并提取发送给客户端的数据?
  • 是的@MatthewHerbst。由于此事件侦听器是在 app.use 调用中处理的,因此只需从那里使用相同的“res”对象。
【解决方案3】:

阅读documentation,这里是res.send的签名:

res.send(body|status[, headers|status[, status]])

这意味着您可以设置自己的状态,例如:res.send( 'some string', 200 ); 甚至只是res.send( 404 );

此方法是您用来发送响应的方法。

一旦发送到客户端,就不能再访问了,所以没有回调。

这是您的服务器做的最后一件事。处理完请求后,它会发送响应。

但是,您可以在将其发送给客户端之前访问它。这意味着您可以:

console.log( res );
res.send( datas );

如果您想回滚/提交,请在调用数据库回调时执行,而不是在响应消失时执行。

【讨论】:

  • 谢谢。从您的回答来看,如果不将 res.send 替换为我自己的版本进行清理然后调用真正的 res.send ,这听起来像是我想做的事情根本不可能。
  • 是的,res.send() 是您的应用程序在处理请求时要做的最后一件事,所以如果您想要任何清理工作,您必须在此之前完成 :)
  • res.on ('header',func) FTW!
  • 答案不正确。请参阅下面有关使用 res.on('finish',...) 附加事件处理程序以在发送响应时触发的答案。
猜你喜欢
  • 2013-05-29
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 2011-07-11
  • 1970-01-01
相关资源
最近更新 更多