Edited at

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

More than 1 year has passed since last update.

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


参考資料