Tosainu Lab

Node.jsで遊んだ (2)

どもどもー

 

前回書いたコードにとんでもない問題があったんで修正したメモです。

興味ある人だけ続きをどうぞ。

 

 

とりあえず前回書いたコードを見なおしてほしい。

 

/*
  main.js
*/

------
// httpリクエストが来た時の動作
function handler (req, res) {
  // index.htmlを読み込んで
  fs.readFile('index.html', function (err, data) {
    if(err) {
      // 無かったら404
    }
    // 表示する
    res.writeHead(200);
    res.write(data);
    res.end();
  });
}
------

さて、これの何が問題かといいますと、例えばTwitterBootstrapを使ったhtmlを表示させようとしてみます。

すると・・・

 

こうなります。

 

理由は簡単です。このサーバーは「どんなリクエストに対してもindex.htmlを返す」仕様です。

外部のcssやjs、画像まで。読み込もうとしたファイルはすべてindex.htmlになりますw

 

さすがにこれでは使い物にならないので修正しました。

 

/*
  main.js
*/

var app = require('http').createServer(handler)
  , io  = require('socket.io').listen(app)
  , fs  = require('fs')
  , mime= require('mime')

app.listen(3000);

function handler (req, res) {
  // Check File Path
  var path;
  if(req.url == '/') {
    path = './index.html';
  }
  else {
    path = '.' + req.url;
  }

  // Read File and Write
  fs.readFile(path, function (err, data) {
    if(err) {
      res.writeHead(404, {"Content-Type": "text/plain"});
      return res.end(req.url + ' not found.');
    }
    var type = mime.lookup(path);
    res.writeHead(200, {"Content-Type": type});
    res.write(data);
    res.end();
  });
}

 

各部分ごとの解説をしていきます。

var app = require('http').createServer(handler)
  , io  = require('socket.io').listen(app)
  , fs  = require('fs')
  , mime= require('mime')

app.listen(3000);

サーバーの作成、必要なモジュールのロード、及びサーバーのポート設定等を行っている部分です。

  • socket.io:Socket.IO通信を使うためのモジュール
  • fs:ファイル読み込みなどのファイルシステム操作モジュール
  • mime:ファイルタイプ判断(後述)のためのモジュール

app.listen(3000);はサーバーのポート設定。今回は3000番ポートです。

 

function handler (req, res) {
  // Check File Path
  var path;
  if(req.url == '/') {
    path = './index.html';
  }
  else {
    path = '.' + req.url;
  }

ここから、リクエストに対する動作の部分になります。

ここではファイルパスの判断を行っています。

まず、req.urlはアクセスされたURLを取得取得するものです。http://hoge.com/fuga/myon.htmlへのアクセスがあった時、req.urlを使うと/fuga/myon.htmlという文字列を取得することができます。

/、つまり何もファイルを指定されなかったらindex.htmlを、そうでなかったら指定されたファイルパスを変数pathに代入しています。

ドキュメントルートはmain.jsと同じディレクトリなので、./filenameのように相対パスで設定しています。

 

  // Read File and Write
  fs.readFile(path, function (err, data) {
    if(err) {
      res.writeHead(404, {"Content-Type": "text/plain"});
      return res.end(req.url + ' not found.');
    }

ファイルの読み込みをおこない、見つからなかった時(他の要因も考えられるけど)の動作です。

fs.readFileで先ほどのpathに代入されたファイルを読み込み、エラーだったら「○○ not found.」と表示させています。

 

    var type = mime.lookup(path);
    res.writeHead(200, {"Content-Type": type});
    res.write(data);
    res.end();
  });
}

ファイルが存在していた時の動作です。ここで注目するのがvar type = mime.lookup(path);です。

pathにより様々なファイルが読み込めるようになったわけですが、Content-Typeを区別してやらないといけないようです。

そこでmimeというモジュールをnpmでインストール、先頭にmime= require('mime')と記述して、mime.lookup(ファイルパス);でContent-Typeを判断できるようです。

ここでは変数typeにContent-Typeを代入し、res.writeHead(200, {"Content-Type": type});というようにしてContent-Typeを指定して出力しています。

 

 

現在作成しているラジコンのコントロールページはほぼ完成といった感じです。

あとはRasPiで動かして、またピン制御等のコードを追加するだけです。

 

さーて、SDはの修理が終わるまでにAVRでのPWM制御をマスターせねば。

ではでは〜