ikemonn's blog

技術ネタをちょこちょこと

【Node.js】httpのエコーサーバを実装してみる

処理のざっくりした流れ

  1. http.ServerがHTTPサーバ機能を実現するサーバオブジェクトを生成する
  2. HTTPクライアントからサーバへのHTTPリクエストが送信される
  3. http.Serverはrequestイベントを発生させる
  4. 受信したリクエスト情報を持つ、http.ServerRequestとHTTPクライアントへ返すレスポンス情報を持つhttp.ServerResponseクラスのオブジェクトの2つが生成される

HTTPのエコーサーバ

// HTTPエコーサーバー HTTPリクエストボディデータを返す
var http = require('http');
var server = http.createServer();
var port = 1337;

// クライアントからリクエストボディデータをレスポンスとして返す
server.on('request', function (req, res) {
    var data = '';
    req.on('data', function(chunk) {
        data += chunk;
    });

    req.on('end', function () {
        res.writeHead(200, {'Content-Type' : 'text/plain'});
        res.end('Body Echo : ' + data + '\n');
    });
});


// HTTPの生データを出力する
server.on('connection', function (socket) {
    console.log('=== Raw Socket Data Start ===');
    socket.on('data', function (chunk) {
        console.log(chunk.toString());
    });

    socket.on('end', function () {
        console.log('=== Raw Socket Data End ===');
    });
});

// ソケット関連のエラー出力
server.on('clientError', function(e) {
    console.log('Client Error: ', e.message);
});

// サーバ関連のエラー出力
server.on('error', function(e) {
    console.log('Server Error: ', e.message);
});

server.listen(port, function () {
    console.log('listening on ' + port);
})

エコーサーバの解説

  1. http.Severはnet.Serverを継承しているので、http.createServer()でHTTPサーバオブジェクト(server)を作成する
  2. listen()でHTTP接続を待ち受ける
  3. HTTPクライアントとTCPのハンドシェイクを行う
  4. server上でconnectionイベントが発生する
  5. この時、リスナにはsocketオブジェクトが渡される
  6. socketオブジェクトのdataイベントリスナでは、HTTPクライアントからsocket通信の受信データを取得できる

httpモジュール内の処理

  1. connectionリスナが呼ばれるとhttp.Server内部でHTTPParserオブジェクトが生成される
  2. HTTPPaserオブジェクトはsocketから受信したHTTPデータを逐次解析し、HTTPのリクエストライン、ヘッダ、ボディなど様々なHTTPリクエスト情報を抽出する
  3. HTTPParserによるHTTPヘッダの解析が終了すると
  4. http.Server上でrequestイベントが発生する
  5. http.Server内部でhttp.ServerRequest(req)とhttp.ServerResponse(res)の2つのオブジェクトを生成し、これらを引数としてあらかじめ登録されたrequestイベントリスナを呼び出す

    • reqにはヘッダ情報(method, url, httpバージョン等)がプロパティ情報として設定されている
    • POSTやPUT,HTTPリクエストによるメッセージボディが含まれているときは、ボディのデータはreq上のdataイベントによって、chunkデータとして逐次リスナに渡される
  6. HTTPリクエストメッセージが全て終了するとreq上でendイベントがよばれる

  7. req上でendイベントが発生するとメッセージボディの取得が全て終了したことになる
  8. リクエスト処理が完了するとHTTPエコーサーバでは受信したデータをresを使ってHTTPヘッダとともに書き出し、レスポンスデータをクライアントに送り返す

参考

サーバサイドJavaScript Node.js入門 (アスキー書籍)

サーバサイドJavaScript Node.js入門 (アスキー書籍)