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

システム開発エンジニアの西田五郎が運営しております。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でAvahi を使ってホスト名でアクセスする

Raspberry PiでAvahiを使ってホスト名でのアクセスを可能にする方法についてです。ホスト名でのアクセスとは192.168.1.10といったIPアドレスではなく、raspberrypi.lo …

Raspberry Piでセンサネットワーク稼働試験(基本編)構成・課題等

Raspberry Piでセンサネットワークを構築して実際に稼働してみます。基本編としてRaspberry Piにセンサを直接接続する構成です。その構成で安定して稼働させるにはどういった課題があるか書 …

Raspberry Piでタッチアプリ開発(その1)ハードウェア構成・開発環境等

Raspberry Piで簡単なタッチアプリを開発する手順について書きます。もちろんですがこれからの手順は一例です。他にもいろいろな方法があると思いますので必要な場合は最適と思われる方法を検討して選択 …

SkyWayでRaspberry Piの遠隔操作(その2)SkyWayからの操作

前回の続きです。全体的にはSkyWayを利用してRaspberry Piの遠隔操作をしてみようという内容です。 前回はRaspberry Pi側でのブラウザ(JavaScript)からMQTT ove …

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

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