13

我想实现这样的目标:

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);

当我为地址卷曲时,控制台出现异常,抱怨标头在发送后无法被打扰,这很公平。只是我不碰响应对象。

/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 层我进入了一个以某种方式暗示如果标头已经发送,则执行路由处理程序必须初始化响应标头的部分。

问题是上述行为是否是故意的(即在路由处理程序完成发送响应后执行任何代码是完全无法想象的,或者这只是连接中的错误?

4

3 回答 3

29

不确定您是否找到了解决方案。

如果你想为请求周期设计一个后处理器,你可以使用一个中间件来监听响应对象上的“完成”事件。像这样:

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();
});

附加到“完成”事件的函数将在响应写出后执行(这意味着 NodeJS 已将响应头和响应体交给操作系统进行网络传输)。

我想这一定是你想要的。

于 2014-02-18T15:30:15.637 回答
2

我认为这是一个糟糕的规划问题。你应该以更好的方式解决这个问题。我不知道为什么你有一个请求处理程序和一个请求后处理器分开,但让我们看看我们能做什么。

所以是的,响应结束后,您无法再次阅读标题。

所以在调用后处理器之前不要完成响应。

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()不是你使用的那种用法。

我希望我的回答对您有所帮助,但我知道它并不能涵盖所有内容,但是您的回答也不是很具体。

于 2012-07-04T23:49:33.183 回答
1

尝试用早晨的咖啡锻炼身体,这是一个多么好的问题啊!

因此proto.js,如果您仔细查看第 102 行,app.handle它是中间件堆栈的处理程序代码,您将看到 next() 是如何运行的。

在调用函数 next() 的地方,您可以看到它检查 res.headerSent 是否为真,如果是则抛出错误。

如果将第 14 行修改为:

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

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

于 2012-07-04T23:52:40.237 回答