株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

Node.js Raspberry Pi

Raspberry PiでのNode.jsの導入(その2)Webサーバ的なプログラム

投稿日:2015年2月28日 更新日:

Raspberry PiでのNode.jsの導入の2回目です。前回はインストールと動作確認でした。今回はもう少しWebサーバ的なプログラムを作成してみます。今現在で日本のNode.jsの公式ページにもリンクがある以下のページを見ながら作成しました。合わせて参照して頂ければと思います。このページは私のようにサーバサイドのJava、PHP等の経験はあるけどサーバサイドのJavaScriptは初めてという方々にはいいかもしれないです。
Nodeビギナーズブック

ここでは上記サイトのプログラムとほぼ同じですが、もう少し簡単に、HTTPでカレントディレクトリの静的ファイルを送信する機能と、特定のURLでは何かの処理を実行するための機能があります。特にRaspberry Pi独自のGPIO等を使っていないのでパソコン等での他のLinuxディストリビューションでも動作すると思います。

ここでの処理は、たとえば、HTMLファイル、cssファイル、画像ファイルがカレントディレクトリに存在する状態で、ブラウザから以下のように表示出来ます。URLは、Raspberry PiでAvahi を使ってホスト名でアクセスするで書いたAvahiを使って、サーバ名.localでアクセスしています。もちろん、IPアドレスでもアクセス出来ました。
0001

特定のURLで以下のように表示だけですが処理出来ます。
0007

ファイルがない場合は以下のように返します。
0009

このように、Webサーバー的な機能がありますが、リクエストをマルチで処理する機能はありません。そのあたりは、Nodeビギナーズブックにブロッキングとノンブロッキングの項目から説明があります。ここではHTTP的な通信が出来ればということにしました。Node.jsでindex.jsから起動出来ます。

ここからプログラムの説明です。JavaScriptの特徴である、関数渡し(匿名関数、匿名関数)、イベント駆動コールバック等を使っていますが、このあたりの説明は省略します。必要な場合は、Nodeビギナーズブック等を参照して下さい。また私も今回初めてNode.jsを使っています。ご了承頂ければと思います。

以下のファイルを作成しました。(Nodeビギナーズブックとほぼ同じですがファイルを返す処理を追加しました。)

index.js – サーバ、ルータ、リクエストハンドラを構成してサーバを起動する。
server.js – 指定されたルータ、リクエストハンドラでHTTPサーバを起動する。
router.js – リクエストのURLからのルーティングの処理を行う。
requestHandlers.js – リクエストごとの各処理の実装。

ファイル一式は以下からダウンロード出来ます。(※単純なテスト的なプログラムです。不具合等は弊社では一切の責任を負いかねます。)
今回のスクリプトとテストファイル一式

index.jsは最後にして、server.jsから書きます。server.jsは以下です。HTTPサーバです。リクエストを受け取るとルーティングへ渡します。

var http = require("http");
var url = require("url");

function start(route, handle) {
	function onRequest(request, response) {
    		var pathname = url.parse(request.url).pathname;
    		console.log("Request for " + pathname + " received.");

		route(handle, pathname, response, request);
  	}

	http.createServer(onRequest).listen(8888);
	console.log("Server has started.");
}
exports.start = start;

router.jsは以下です。ルーティングの処理です。実際はルーティングの処理というほどでもないですが、特定の機能のURLであればその処理(ハンドラ)を設定して、それ以外は静的ファイルが指定されていればそのファイルを読み込んでハンドラへ渡します。それ以外はそれらしいHTTPステータスのハンドラへ渡します。

var fs = require("fs")

function route(handle, pathname, response, request) {
	console.log("About to route a request for " + pathname);

	if (typeof handle[pathname] === 'function') {
		handle[pathname](response, request);
	} 
	else 
	{
		pathname = "." + pathname;

		fs.exists(pathname, function(exists){
        		console.log(pathname+" "+exists);
        		
			if (!exists) { 
				handle["http404"](response); 
				return; 
			}
        		fs.readFile(pathname, "binary", function(err, file){
                		if (err) { 
					handle["http500"](err); 
					return ; 
				}
                		handle["http200"](file, response);  
        		});
		});
  	}
}
exports.route = route;

requestHandlers.js は以下です。start()がデフォルトの処理で、action1()、action2()が特定の処理を想定していて、http200()からがhttpの処理的なハンドラです。http200()でファイルを返しています。

var querystring = require("querystring")
var fs = require("fs")

var header = {
"Pragma": "no-cache",
"Cache-Control" : "no-cache"
}

function start(response) {
	console.log("Request handler 'start' was called.");

	response.writeHead(200, header);
	response.end("start\n")
}

function action1(response, request) {
	console.log("Request handler 'action1' was called.");

	response.writeHead(200, header);
	response.end("action1\n")
}

function action2(response) {
  	console.log("Request handler 'action2' was called.");

	response.writeHead(200, header);
	response.end("action2\n")
}

function http200(file,response){
	console.log("Request handler '200' was called.");

	response.writeHead(200, header);
	response.write(file, "binary");
	response.end();
}

function http404(response){
	console.log("Request handler '404' was called.");

	response.writeHead(404, header);
	response.end("http404");
}

function http500(response){
	console.log("Request handler '500' was called.");

	response.writeHead(500, header);
	response.end("http500");
}

exports.start = start;
exports.action1 = action1;
exports.action2 = action2;

exports.http200 = http200;
exports.http404 = http404;
exports.http500 = http500;

最後にindex.jsです。このindex.jsから、Node index.jsとして起動します。上記のサーバ、ルータ、リクエストハンドラを構成してサーバを起動します。

var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = {};
handle["/"] = requestHandlers.start;
handle["/action1"] = requestHandlers.action1;
handle["/action2"] = requestHandlers.action2;

handle["http200"] = requestHandlers.http200;
handle["http404"] = requestHandlers.http404;
handle["http500"] = requestHandlers.http500;

server.start(router.route, handle);

プログラムは以上です。実際には特定の処理としている action1()、action2()では何もしていなので、テスト的なプログラムになっています。それでもファイルを返す場合と分岐出来たので最初としてはいいかと思っています。またマルチでのリクエスト処理も課題です。

但しですが、Node.jsの場合はWebアプリケーションを作成する場合は、Expressに代表されるフレームワークを使うのが一般的かとは思います。今回はここまでですが、またいろいろと書きたいと思います。


AdSense

AdSense

-Node.js, Raspberry Pi

執筆者:

関連記事

Raspberry PiでIoT(温度・湿度・気圧データ編 その1)BME280でデータ取得

Raspberry PiでIoTに取り組んでみるという内容で実際に動作させながら書きたいと思います。まずは、IoTとは、Internet of Thingsの略です。もう既にこの言葉も普及していて様々 …

温度センサADT7410(その1)i2C通信とは

温度センサのADT7410を使ってみます。ADT7410はアナログ・デバイセズ社の製品ですが、実際には以下の秋月さんのモジュールを使います。 ADT7410使用 高精度・高分解能 I2C・16Bit …

SkyWayの利用(その4)Raspberry Piでの利用

前回の続きです。NTTコミュニケーションズ株式会社提供のリアルタイムコミュニケーションのためのプラットフォームであるSkyWayを使ってみます。前回はJavaScriptでカメラとマイクのストリーミン …

Raspberry PiでIoT(MQTTで遠隔操作編 その4)Raspberry PiのGPIOとHeroku連動Pub編

Raspberry PiでIoT MQTTで遠隔操作編の4回目です。2台のRaspberry Piでインターネット経由でGPIOを操作するというテーマで書いています。 前回はMQTTのSub側となるR …

Kivyでの画面遷移(Screen Managerの使い方)について

Raspberry Piの環境でKivyを使っています。今回は画面遷移についてです。その画面遷移のためにScreen Managerというwidgetを使ってみます。 今現在のRaspberry Pi …