LoginSignup
35
47

More than 5 years have passed since last update.

Nodejs HTTP/HTTPS サーバーとクライアントのコーディングパターン

Last updated at Posted at 2017-05-07

node.js の express フレームワークを利用しないで、HTTP/HTTPSサーバーと対応するクライアントのコーディング・パターンの忘備録です。

低レベル HTTPサーバー

nodeで"Hello world"を返すHTTPサーバーのコードです。 次のコードは、リクエストがあった時のイベントハンドラーを登録しておき、このHTTPサーバーにイベントが発生したら無条件に"Hello world"を返します。

node.js
var http = require('http');

// Webサーバーの作成
var server = http.createServer();

// イベントハンドラを登録する
server.on('request',function(req,res) {
    res.writeHead(200,{'Content-Type': 'text/plain'});
    res.write('Hello world\n');
    res.end();
})

// イベントの待機
server.listen(3000);

ソースコード: h100_http_server.js

curlコマンドでの実行結果

GETの場合で、curl コマンドを利用したケースです。

$ curl -X GET http://192.155.208.116:3000/
Hello world

GETの場合で、パラメータやフォルダやファイルしてを付与した場合は、サーバー側の処理で受け取る必要があります。

$ curl -X GET http://192.155.208.116:3000/function?query=10
Hello world

POSTの場合でも同様です。

$ curl -X POST http://192.155.208.116:3000/function?query=10
Hello world

サーバー側でのリクエストの表示

サーバー側でメソッドとフォルダとパラメータを表示するには、イベントハンドラに登録するコールバックに以下のコードを追加します。

server.on('request',function(req,res) {
    // リクエストの表示
    console.log("Method = ", req.method);
    console.log("URL = ", req.url);

コールバック関数の中身を表示する。

登録済みのコールバック関数を表示するには、リスナーのイベント待ちに入る前に以下のコードを実行すると内容をリストする事ができます。

x = server.listeners('request');
console.log(x[0].toString());

HTTPサーバーでデータを受け取る

次はクライアントから送信されるデータをサーバーで受け取るパターンです。その前にHTTPクライアントのコードを作成します。

HTTPクライアントの開発 JSONデータを送信

以下がHTTPクライアントから、GETでJSONデータを送信するコードです。

var http = require("http");
var querystring = require("querystring");
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');

// 送信データ作成
var json_data = {
    message: 'Hello World! こんにちは',
    sound: 123
}
var qs_data = querystring.stringify(json_data);
var options = {
    hostname: '192.155.208.116',
    port: 3000,
    path: '/rest',
    method: 'GET',
    headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(qs_data)
    }
};

// リクエスト定義と応答処理設定
var req = http.request(options, function(res) {
    console.log("STATUS: ", res.statusCode);
    console.log("HEADERS: ", JSON.stringify(res.headers));
    res.setEncoding('utf8');

    // 応答受信処理
    res.on('data', function(chunk){
    console.log("BODY: ", chunk);
    // Query String -> JSON形式へ変換
    var rcv_text = querystring.parse(decoder.write(chunk))
        var rcv_json_text = JSON.stringify(rcv_text);
        var rcv_json = JSON.parse(rcv_json_text);
        console.log("json text = ", rcv_json.message);
        console.log("json number = ", rcv_json.sound);
        console.log("json boolean = ", rcv_json.reply);
    });
    // 応答終了処理
    res.on('end', function(){
    console.log('これ以上データはありません。')
    });
});
// 送信のエラー処理
req.on('error', function(e){
  console.log( "エラー発生: ", e.message);
});
// データ送信(GET)
req.write(qs_data);
req.end();

ソースコード:
h201_http_get.js

データ送受信に必要なモジュールの読み込み部分です。 HTTPリクエストに付与できる形式に変換するquerystringt と、応答メッセージを受け取る時のデコード文字コードを設定します。

var querystring = require("querystring");
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');

以下は、JSON形式でサーバーへ送信するデータ json_data をQuery String 形式へ変換します。そして、optionsに送信先や内容を定義したデータをセットして、リクエストを作成時に利用します。

var json_data = {
    message: 'Hello World! こんにちは',
    sound: 123
}
var qs_data = querystring.stringify(json_data);
var options = {
    hostname: '192.155.208.116',
    port: 3000,
    path: '/rest',
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(qs_data)
    }
};

次のコードは、サーバーへのリクエストの定義と、サーバーからの応答を処理するコールバック関数の定義です。このコードからは実際にリクエストが送信されるものではありません。

var req = http.request(options, function(res) {
    console.log("STATUS: ", res.statusCode);
    console.log("HEADERS: ", JSON.stringify(res.headers));

    // 応答受信処理                                                                            
    res.on('data', function(chunk){
        console.log("BODY: ", chunk);
        // Query String -> JSON形式へ変換                                                      
        var rcv_text = querystring.parse(decoder.write(chunk))
        var rcv_json_text = JSON.stringify(rcv_text);
        var rcv_json = JSON.parse(rcv_json_text);
        console.log("json text = ", rcv_json.message);
        console.log("json number = ", rcv_json.sound);
        console.log("json boolean = ", rcv_json.reply);
    });
    // 応答終了処理                                                                            
    res.on('end', function(){
        console.log('これ以上データはありません。')
    });
});

次のコードは、クライアントからサーバーへ送信する際に、エラーが発生した時にコールバックされる関数です。

req.on('error', function(e){
  console.log( "エラー発生: ", e.message);
});

例えば、サーバーが停止していた場合、次の様にメッセージが表示されます。

$ ./h201_http_get.js 
エラー発生:  connect ECONNREFUSED

先に設定したリクエストを送信するためのコードが次です。 このコードが実行されるとリクエストが送信されます。

// データ送信(GET)                                                                             
req.write(qs_data);
req.end();

ソースコード: h201_http_get.js

POSTで送信するクライアント

POSTリクエストを送信するには、options の method を POST に変更します。ついでに変数名も変更しておきます。

var post_data = querystring.stringify(json_data);
var options = {
    hostname: '192.155.208.116',
    port: 3000,
    path: '/upload',
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(post_data)
    }
};

コードが読み易くなる様に、同じく変数名も変更しておきます。

// データ送信(POST)                                                                            
req.write(post_data);
req.end();

ソースコード: h200_http_post.js

HTTPサーバーで送信データを受け取るコードの開発

次は、クライアントが出来たのでサーバー側を開発します。 低レベルのHTTPサーバーのコードに、受信データをJSON形式に変換するためのモジュールを追加します。

var querystring = require("querystring");
const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');

さらに、コールバック関数の中で、Query String から JSON 形式の変数に格納するコードを追加します。さらに、受けたデータに情報を付加して返信します。

server.on('request',function(req,res) {

    // リクエストの表示
    console.log("Method = ", req.method);
    console.log("URL = ",    req.url);

    // POSTデータ受信処理
    req.on('data',function(chunk) {
    console.log("header = ", req.headers);
    // Query String -> JSON形式へ変換
    var rcv_data = querystring.parse(decoder.write(chunk))
    var rcv_text = JSON.stringify(rcv_data);
    var rcv_json = JSON.parse(rcv_text);
        console.log("json text = ", rcv_json.message);
        console.log("json number = ", rcv_json.sound);
        console.log("json boolean = ", rcv_json.reply);

    // 何かの処理
    rcv_json.message = "こんにちは、良い天気ですね。";
    rcv_json.reply = true;

    // 応答送信
    res.writeHead(200,{'Content-Type': 'application/json'});
    var text_data = JSON.stringify(rcv_json);
    var ReplyData = querystring.stringify(rcv_json);
    res.write(ReplyData);
    res.end();
    });

});

ソースコード: h102_http_server2.js

実行結果 サーバーサイド GETの場合

Method =  GET
URL =  /rest
header =  { 'content-type': 'application/json',
  'content-length': '80',
  host: '192.155.208.116:3000',
  connection: 'close' }
json text =  Hello World! こんにちは
json number =  123
json boolean =  undefined

実行結果 サーバーサイド POSTの場合

Method =  POST
URL =  /upload
header =  { 'content-type': 'application/x-www-form-urlencoded',
  'content-length': '80',
  host: '192.155.208.116:3000',
  connection: 'close' }
json text =  Hello World! こんにちは
json number =  123
json boolean =  undefined

低レベル HTTPSサーバー

次は、低レベルのHTTPサーバーのコードに加えて、HTTPS サーバーにアップグレードしていきます。

ドメイン名

HTTPSサーバーを作るには、サーバーのIPアドレスに、DNS名と証明書を取得する必要があります。 無料でドメイン名を取得するには、MyDNSが便利です。

証明書

無料の証明書を取得するには、Let's Encrypt を利用して取得することができます。 先に作成したドメイン名を使って証明書を作成します。

コード追加部分

JSON形式で、key と cert を読み込んで、httpsサーバー作成の関数にセットします。 これで、HTTPSサーバーへのアップグレード完了です。

var fs = require('fs');
var https = require('https');
中略
var options = {
  key:  fs.readFileSync('../lets_encript.key'),
  cert: fs.readFileSync('../lets_encript_fullchain.crt')
};
server = https.createServer(options);

ソースコード: h101_https_server.js

curlコマンドの実行結果

IPアドレスでアクセスした場合、以下の様にエラーが発生します。

$ curl -X GET https://192.155.208.116:3000/
curl: (51) SSL: certificate subject name 'www.mahotakara.wjg.jp' does not match target host name '192.155.208.116'

DNS名でGETでアクセスした結果です。

$ curl -X GET https://www.mahotakara.wjg.jp:3000/
Hello world

同様にPOSTでアクセスした結果です。
~~~
$ curl -X POST https://www.mahotakara.wjg.jp:3000/
Hello world
~~~

HTTPSサーバーでデータを受け取る

低レベルのHTTPSサーバーに、コードを加えます。 加えるポイントは、HTTPサーバーのケースと同じです。

ソースコード: h103_https_server2.js

HTTPSクライアントの開発

追加する内容は、HTTPクライアントと同じです。

GETのソースコードです。 h203_https_get.js しかし、秘匿性が必要な場合は、GETを利用してはいけません。その理由は、IPAのウェブ記事の「クエリストリングから情報が漏れる」を参考にしてください。

POSTのケース
こちらが、本番利用にオススメのPOSTの場合のソースコード h202_https_post.jsです。

POST実行結果

クライアント側のコンソール・ログ出力

$ ./h202_https_post.js 
STATUS:  200
HEADERS:  {"content-type":"application/json","date":"Sun, 07 May 2017 07:21:46 GMT","connection":"close","transfer-encoding":"chunked"}
BODY:  message=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E3%80%81%E8%89%AF%E3%81%84%E5%A4%A9%E6%B0%97%E3%81%A7%E3%81%99%E3%81%AD%E3%80%82&sound=123&reply=true
json text =  こんにちは、良い天気ですね。
json number =  123
json boolean =  true
これ以上データはありません。

サーバー側のコンソール・ログ出力

Method =  POST
URL =  /upload
header =  { 'content-type': 'application/x-www-form-urlencoded',
  'content-length': '80',
  host: 'www.mahotakara.wjg.jp:3000',
  connection: 'close' }
json text =  Hello World! こんにちは
json number =  123
json boolean =  undefined

参考資料

35
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
47