Node.js

http.ClientRequest の request.write() によるデータ送信のタイミング

More than 5 years have passed since last update.

質問:

書籍:「サーバサイドJavaScript Node.js入門」の p186 10.4 HTTPクライアントの概要 で

最終的にreq.end() メソッドによって保存されたHTTPリクエストデータがサーバ側に初めて送信されます(図10-9)。

と書いてあるけど、実際動作確認してみるとreq.end()より前にデータが送られているように見える。記述の間違いじゃないか?

と質問を受けました。

そこで、 http.ClientRequestreq.write()の挙動(どのタイミングでデータは送られるのか)ということを調べました。

回答:

テキストの記載が間違いでした。req.end()の有無に関係なくreq.write()の実行によりサーバ側へHTTPリクエストのボディデータは送信されます。

理由:

ソースを確認したら、req.write()するとソケットに接続していればその時点でソケットにデータを書き込む処理を行っていました。よって req.end()がなくてもHTTPリクエストのボディデータはサーバ側に送信されます。

じゃなぜ間違えたの?:

下記の様に単純な HTTPクライアントリクエストを行うコードでは、client.write()falseだったので、どんな状況でも単純に req.write()では出力バッファに溜り、req.end()で出力バッファをフラッシュ&送信しているものと思い込んでました。(私の確認不足です。)

request1.js
var http = require('http');
var req = http.request({port:8080, method:'POST'});
console.log(req.write('a')); // false 出力バッファに溜まる
console.log(req.write('b')); // false 出力バッファに溜まる
req.end('c'); // false サーバに送信?

上記 request1.js でclient.write()falseになってデータが出力バッファに溜まっている理由は、req.write()実行時にHTTPクライアントの socket 接続がまだ完了してないからです。

下記コードのように socket 接続が完了した後に client.write() すれば、実行時に直ちにデータはサーバに送信されます。

request2.js
var http = require('http');
var req = http.request({port:8080, method:'POST'});
req.on('socket', function(socket) {
  socket.on('connect', function() {
    console.log(req.write('a')); // true サーバに送信
    console.log(req.write('b')); // true サーバに送信
    req.end('c'); // Chunk終了の"0\r\n\r\n"をサーバに送信
  });
});

よってテキストp186の記述は間違いで、

req.write() は、リクエストオブジェクトのソケット接続が完了していれば、直ちにデータをサーバに送信します。ソケットが未接続の場合やエージェントからソケットの割り当てがまだされていない場合は、データは出力バッファに溜まります。

と書くのが正しい表現でした。近日中に正誤表を更新いたします。