10

以下のコードでは、 req.pipe(res) が機能しない理由がわかりませんが、エラーもスローされません。これは nodejs の非同期動作によるものだと推測されますが、これはコールバックのない非常に単純なケースです。

私は何が欠けていますか?

http.createServer(function (req, res) {

  res.writeHead(200, { 'Content-Type': 'text/plain' });

  res.write('Echo service: \nUrl:  ' + req.url);
  res.write('\nHeaders:\n' + JSON.stringify(req.headers, true, 2));

  res.write('\nBody:\n'); 

  req.pipe(res); // does not work

  res.end();

}).listen(8000);

カールは次のとおりです。

➜  ldap-auth-gateway git:(master) ✗ curl -v -X POST --data "test.payload" --header "Cookie:  token=12345678" --header "Content-Type:text/plain" localhost:9002 

デバッグ出力は次のとおりです (本文がアップロードされたことを確認してください)。

  About to connect() to localhost port 9002 (#0)
  Trying 127.0.0.1...
    connected
    Connected to localhost (127.0.0.1) port 9002 (#0)
  POST / HTTP/1.1
  User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5
  Host: localhost:9002
  Accept: */*
  Cookie:  token=12345678
  Content-Type:text/plain
  Content-Length: 243360
  Expect: 100-continue

  HTTP/1.1 100 Continue
  HTTP/1.1 200 OK
  Content-Type: text/plain
  Date: Sun, 04 Aug 2013 17:12:39 GMT
  Connection: keep-alive
  Transfer-Encoding: chunked

サービスは、リクエスト本文をエコーせずに応答します。

Echo service: 
Url:  /
Headers:
{
  "user-agent": "curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5",
  "host": "localhost:9002",
  "accept": "*/*",
  "cookie": "token=12345678",
  "content-type": "text/plain",
  "content-length": "243360",
  "expect": "100-continue"
}

...そして最終的なcurlデバッグは

Body:
 Connection #0 to host localhost left intact
 Closing connection #0

さらに、大きなリクエスト本文でストレス テストを行うと、EPIPE エラーが発生します。どうすればこれを回避できますか?

-- 編集: 試行錯誤の結果、これが機能するようになりましたが、まだタイミングの問題が指摘されています。タイムアウトによりペイロードが返されるため、これはまだ奇妙ですが、タイムアウト期間は気にしません。つまり、タイムアウトを 5 秒または 500 秒に設定しても、ペイロードはリクエストに適切にパイプされ、接続は終了します。

編集は次のとおりです。

http.createServer(function (req, res) {

    try {
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
      res.write('\nBody:"\n');
      req.pipe(res);
    } catch(ex) {
      console.log(ex);
      // how to change response code to error here?  since headers have already been written?
    } finally {
      setTimeout((function() {
        res.end();
      }), 500000);
    }

}).listen(TARGET_SERVER.port);

?

4

2 に答える 2

8

req を res にパイプします。Req は読み取り可能なストリームであり、response は書き込み可能なストリームです。

   http.createServer(function (req, res) {

       res.writeHead(200, { 'Content-Type': 'text/plain' });    
       res.write('Echo service: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));

       // pipe request body directly into the response body
       req.pipe(res);       

   }).listen(9002);
于 2013-07-31T03:48:03.763 に答える
6

最初に、カールがオフになっているように見えます。ここに示すように、投稿されたデータのファイル名の前に @ を付ける必要があります。それ以外の場合は、ファイル名を投稿するだけです。

それとは別に、Chandu は、res.end()ここでの呼び出しが問題であると言っています。

ノードでは IO が非同期であるため、.pipeコマンドを発行すると、パイプがバックグラウンドで動作している間に、制御がすぐに現在のコンテキストに返されます。次に を呼び出すとres.end()、ストリームが閉じられ、それ以上データが書き込まれなくなります

ここでの解決策は、デフォルトである.pipeストリーム自体を終了させることです。

異なるマシンと異なるデータサイズでは、書き込み可能なストリームの終了イベントが完全に処理される前に、非同期 IO が理論的に終了する可能性があるため (小さなデータセットの高速 IO)、タイミングが関係していると思います。

より多くのコンテキストについては、このブログ投稿をお勧めします。

于 2013-08-06T18:31:17.250 に答える