javascript 如何让NodeJS/connect中间件在responde.end()被调用后执行?

c3frrgcw  于 2023-05-21  发布在  Java
关注(0)|答案(3)|浏览(105)

我想实现这样的目标:

var c = require('connect');
var app = c();

app.use("/api", function(req, res, next){
    console.log("request filter 1");
    next();
});

app.use("/api", function(req, res, next){
    console.log("request filter 2");
    next();
});

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    next();
});

app.use("/api", function(req, res, next){
    console.log("response post processor");
    next();
});
app.listen(3000);

当我 curl 的地址,我得到一个异常的控制台抱怨头不能被打扰后,被发送,这是公平的。只是我不碰回应对象。

/usr/bin/node app2.js
request filter 1
request filter 2
request handler
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
    at ServerResponse.res.setHeader (/home/zpace/node_modules/connect/lib/patch.js:59:22)
    at next (/home/zpace/node_modules/connect/lib/proto.js:153:13)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:25:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:19:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:14:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Function.app.handle (/home/zpace/node_modules/connect/lib/proto.js:198:3)

在调试NodeJS/Connect层时,我进入了一个部分,这意味着如果已经发送了头,那么执行路由处理程序必须初始化响应头。
问题是,如果上述行为是故意的(即在路由处理程序完成发送响应后执行任何代码是完全不可想象的,或者这只是连接中的一个错误?)

sulc1iza

sulc1iza1#

我不确定你是否找到了解决方案。
如果你想为请求周期设计一个后处理器,你可以使用一个中间件来监听响应对象上的“完成”事件。像这样:

app.use(function(req, res, next){
  res.on('finish', function(){
    console.log("Finished " + res.headersSent); // for example
    console.log("Finished " + res.statusCode);  // for example
    // Do whatever you want
  });
  next();
});

附加到“finish”事件的函数将在响应被写出后执行(这意味着NodeJS已经将响应头部和主体移交给OS进行网络传输)。
我想这一定是你想要的。

vsaztqbk

vsaztqbk2#

我认为这是一个糟糕的规划问题。你应该用更好的方式解决这个问题。我不知道为什么你有一个请求处理程序和一个请求后处理程序分开,但让我们看看我们能做什么。
所以,是的,响应结束后,你不能再次阅读标题。
所以在调用后处理器之前不要完成响应。

var isEnd;

app.use("/*", function(req, res, next){
  isEnd = false;
})

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.write("hello");
    isEnd = true;
    next();
});

app.use("/api", function(req, res, next){
    console.log("response post processor");
    if(isEnd) {
        res.end();
    }
    else next();
});

这是一种解决方案,但这可能不是解决您的问题的最佳方法。
在我看来,在响应完成后调用next()真的很糟糕。如果你需要一个后处理器,为什么你在请求过滤器中这样做(或者这是什么)。调用函数但不调用next()
也许是这样:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    setTimeout(function(){(postProcessor(req)},0);
});

function postProcessor(req) {
//doing post process stuff.
//response not needed because already ended.
}

或者这个:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.writed("hello");
    setTimeout(function(){(postProcessor(req)},0);
    // u cant res.end here because setTimeout. 
    //If you dont use setTimeout you can use res.end here, but not bot function.
});

function postProcessor(req, res) {
//doing post process stuff.
res.end();
}

next()不是为那个用途,你用的。
我希望我的回答对你有帮助,但我知道它不能涵盖一切,但你的回答也不是很具体。

bq9c1y66

bq9c1y663#

这是一个多么好的问题,可以在早上喝咖啡的时候试试!
因此,浏览proto.js,如果向下查看第102行app.handle,它是中间件堆栈的处理程序代码,您将看到next()是如何操作的。
在调用next()函数的地方,您可以看到它检查res.headerSent是否为true,如果是,则抛出错误。
如果将第14行修改为:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    console.log(res);
    next();
});

您将看到它实际上将“headersSent”设置为true。因此,在我们结束请求之后,您可以从next()代码中看到,由于所讨论的条件,它抛出了错误。

相关问题