node.js の express フレームワークを利用しないで、HTTP/HTTPSサーバーと対応するクライアントのコーディング・パターンの忘備録です。
低レベル HTTPサーバー
nodeで"Hello world"を返すHTTPサーバーのコードです。 次のコードは、リクエストがあった時のイベントハンドラーを登録しておき、このHTTPサーバーにイベントが発生したら無条件に"Hello world"を返します。
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