0utputab1e

[ JavaScript ] HTMLページを動かす簡易サーバをつくってみた

HTMLやCSS、JSをローカルホストで見れるサーバがほしくて、「JSファイル1つ」でつくったので、気づきなどをまとめておこうと思います。

前提

  • node: v12.18.3

構成

以下のようにファイル構成してみました。

$ tree
.
├── index.html
├── index.css
└── server.js

0 directories,, 3 files

サーバ用スクリプトの作成

以下がファイルの全体像です。

var http = require('http');
var fs = require('fs');
var path = require('path');

http.createServer(function(request, response){
    console.log('request ', request.url);

    var filePath = '.' + request.url;
    if (filePath == './') {
        filePath = './index.html'
    }

    var extname = String(path.extname(filePath)).toLowerCase();
    var mimeTypes = {
        '.html': 'text/html',
        '.js': 'text/javascript',
        '.css': 'text/css'
    };

    var contentType = mimeTypes[extname] || 'application/octet-stream';

    fs.readFile(filePath, function(error, content){
        if (error) {
            if (error.code == 'ENOENT') {
                fs.readFile('./404.html', function(){
                    response.writeHead(200, {'Content-Type': contentType});
                    response.end(content, 'utf-8');
                });
            } else {
                response.writeHead(500);
                response.end('Sorry, check with the site admin for error: ' + error.code + '..\n');
                response.end();
            }
        } else {
            response.writeHead(200, {'Content-Type': contentType});
            response.end(content, 'utf-8');
        }
    });
}).listen(3002);
console.log('Server running at http://127.0.0.1:3002');

順番に説明していきます。

モジュール呼び出し部分

このサーバはNode.jsで動かすので

var http = require('http');

のように「require」でモジュールを呼び出しています。

※今回は関係ないですが、この「require」をクライアントサイドで実行する場合、Webpackなどで依存解決する必要があるようです

サーバの定義、起動ロジック

サーバの主要ロジックは

http.createServer(function(request, response){ ... }).listen(<待受ポート番号>);

で定義しています。

http.createServer()内で定義したサーバを指定のポートで待ち受けさせます。

パスの判定ロジック

アクセスがあったURLパスを判定するときは

var filePath = '.' + request.url;
if (filePath == './') {
    filePath = './index.html'
}

で判定しています。

URLパスなしでアクセスされたらプロジェクトルート直下のindex.htmlを表示します。

 
もしスクリプトのどこかで、アクセスされたファイルの拡張子を文字列で抽出したい場合

String(path.extname(<ファイル名>))

で取得可能です。末尾に「.toLowerCase()」とすれば、取得した拡張子文字列を全部小文字に変換できます。

レスポンスの判定ロジック

リクエストされたファイルをfsモジュールで読み取って、以下のようにレスポンスの表示に利用しています。

fs.readFile(filePath, function(error, content){
    if (error) {
        if (error.code == 'ENOENT') {
            fs.readFile('./404.html', function(){
                response.writeHead(200, {'Content-Type': contentType});
                response.end(content, 'utf-8');
            });
        } else {
            response.writeHead(500);
            response.end('Sorry, check with the site admin for error: ' + error.code + '..\n');
        }
    } else {
        response.writeHead(200, {'Content-Type': contentType});
        response.end(content, 'utf-8');
    }
});

 
HTTPレスポンスヘッダーは、

response.writeHead(<ステータスコード>, {'Content-Type': <コンテンツタイプ>});

でセットしています。response.writeHeadの引数はそれぞれ

  • 第1引数にステータスコード
  • 第2引数にその他のヘッダーのキーと値

を渡しますが、この例ではオブジェクト化した「mimeTypes」から、アクセスされたURLパスの拡張子をキーにContent-Typeを取り出し、writeHeadの第二引数に渡しています。

 
mimeTypesの中にない拡張子でアクセスされたら、デフォルトで「application/octetstream」になるようにしています。

 
HTTPレスポンスボディに文字列を出力する点では

  • response.write(str)
  • response.end(str)

は役割が似ていますが、後者は同時にEOF(ファイルの終端)も出力するようになっています。

 
また、エラーの場合

  • 404: 「./404.html」を探し404エラーページを表示
  • 500: エラーメッセージを表示

で対策しています。

 
なにもなければステータスコード200でレスポンスヘッダをセットし、読み取ったファイルをレスポンスボディに書き込んで返します。

ターミナルから起動

サーバ用スクリプトができたら、ターミナル上で

$ node ./server.js

と入力しましょう。すると

$ node server.js
Server running at http://127.0.0.1:3002

のようにサーバが待ちになるので、ブラウザからアクセスすればOKです。

 
ちなみにリクエストを受け付けると

$ node server.js
Server running at http://127.0.0.1:3002
request  /
request  /favicon.ico

と続けて出力されるようになっています。

最後に

簡単にHTML、CSS、JSの動く環境がほしくなったので「これ一個で動くサーバ」を組んでみましたが、ライブリロード機能がないなど最低限のため、既成の環境に及ばない点は否めないです。

ちゃんと開発に使いたいのであれば、npmやyarnでプロジェクトをたてたほうがよさそうです。

ですが、自分で仕組みを見ながら作ってみるのも勉強になるので、とりあえずやってみるのもアリだと思ったのでした。

 
では、このへんで!

 
参考:
モジュール化(importとrequireの違い) | わくわくBank
node.jsに入門してみる。2 ~基本的な機能に触れてみる編~ | pxt.jp

 

あわせて読みたい記事

>> Homeに戻る