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

システム開発エンジニアの西田五郎が運営しております。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でC言語版Lチカを試す(その1)デバイスドライバ利用

Raspberry PiでC言語を使ったLEDの点灯、消灯(いわいるLチカ)を試してみました。やはりGPIOの入出力に関してはこのLチカをやってみないと始まらないというところでしょうか。今回はGPIO …

Raspberry Piでタッチアプリ開発(その4)ボタンとGPIOの連動

Raspberry Piでタッチアプリ開発の4回目です。前回作成したレイアウトとボタンのコールバックにGPIOの処理を組み込みます。そして、このアプリを自動起動するように設定します。 (※2021/0 …

Raspberry PiでIoT(MQTTで遠隔操作編 その1)MQTTでの通信

Raspberry PiでIoTのMQTTで遠隔操作編のシリーズを始めます。実際に動作させてみるということを重点として進めます。ここでの遠隔操作は2台のRaspberry Pi間でインターネット経由の …

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

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

Raspberry PiでIoT(MQTTで遠隔操作編 その2)MQTT Brokerの構築とPythonでのpub/sub

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