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

「finish」イベントに関連付けられた関数は、応答が書き出された後に実行されます(つまり、NodeJSはネットワーク送信のために応答ヘッダーと本文をOSに渡します)。

私はこれがあなたが望むものでなければならないと思います。

于 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がtrueであるかどうかをチェックし、trueである場合はエラーをスローすることがわかります。

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 に答える