node.js 超入門②webサーバを作る(ルーティングもやってみる)


[前回](http://qiita.com/ritukiii/items/7f28554369d63eb373c3)は、簡単なwebサーバを作ってみました。
今回はよりwebサーバっぽく、リクエストによって処理を分けたり、
HTMLを表示させたりしてみましょう。

## (基礎知識)ファイルを分割する

node.jsでは、1つのファイルに様々な処理をつらつらと書いていく事も可能ですが、
実際に処理を書いていくと、ファイルを分けて行きたくなると思います。

その時、外部ファイルに切り出した情報をどうやって使うのかを知っておきましょう。

node.jsでは、デフォルトで`exports`という機能が備わっているのでそれを使ってみます。
[前回](http://qiita.com/ritukiii/items/7f28554369d63eb373c3)作ったwebサーバで、共通化出来そうな部分として、port番号だけ外のファイルに切り出してみます。

```config.js
exports.port = 3000;
```

このように、`exports`を使うと、`port`という変数を呼び出し元から使えるようになります。

使う為には3ステップです。

- 1. 外部ファイルに使いたい変数を、`exports.{変数名} = xxx`と定義する
- 2. 呼び出し元で、`var hoge = require('./xxxx')`と呼び出す
- 3. `hoge.{変数名}`で外部ファイルの値を使う

では、server.jsから使ってみましょう。

```server.js
// nodeのコアモジュールのhttpを使う
var http = require('http');
var config = require('./config');
var server = http.createServer();

server.on('request', function(req, res) {
    res.writeHead(200, {'Content-Type' : 'text/plain'});
    res.write('hello world');
    res.end();
});

// サーバを待ち受け状態にする
// 第1引数: ポート番号
// 第2引数: IPアドレス
server.listen(config.port);

console.log(config.port);
```

```bash
$ node server.js
ポート番号: 3000
```

読み込めてますね。
このように`exports`はかなり使っていくと思うので覚えておきましょう。

## リクエストのURL毎に処理を分けてみる

処理されたリクエストURLは、`req`の`url`に入ってますので、実際に見てみましょう。
前回`hello world`としていた部分を、どのURLから来たかに変えてみます。

```server.js
// nodeのコアモジュールのhttpを使う
var http = require('http');
var config = require('./config');
var server = http.createServer();

server.on('request', function(req, res) {
    res.writeHead(200, {'Content-Type' : 'text/plain'});
    res.write('request from: ' + req.url);
    res.end();
});

// サーバを待ち受け状態にする
// 第1引数: ポート番号
// 第2引数: IPアドレス
server.listen(config.port);

console.log('ポート番号: ' + config.port);
```

**hoge.htmlにアクセスしてみる**

![スクリーンショット 2017-09-09 12.02.39.png](https://qiita-image-store.s3.amazonaws.com/0/23276/89d09ac4-65e5-8912-8421-a9cbb2c8bf66.png "スクリーンショット 2017-09-09 12.02.39.png")

**hoge.html?fuga=fooにアクセスしてみる**

![スクリーンショット 2017-09-09 12.02.34.png](https://qiita-image-store.s3.amazonaws.com/0/23276/8b5b03e8-eeb3-7b45-d794-2c0abf6cdd01.png "スクリーンショット 2017-09-09 12.02.34.png")

リクエストURLが取れているのが分かりました。

## リクエスト毎に処理を分けてみる

`req.url`にリクエストのURLが入っているのが分かったので、これを使って処理を分けてみます。

`/about`と`/company`で来たときにそれぞれ別のメッセージをだして、
それ以外のリクエストだった場合は、`page not found`と表示してみます。

```
// nodeのコアモジュールのhttpを使う
var http = require('http');
var config = require('./config');
var server = http.createServer();
var msg;

server.on('request', function(req, res) {
    res.writeHead(200, {'Content-Type' : 'text/plain'});

    // リクエストされた処理により表示内容を分けてみる
    switch (req.url) {
        case '/about':
            msg = 'welcome about page';
            break;
        case '/company':
            msg = 'welcome my company page';
            break;
        default:
            msg = 'page not found';
            break;
    }
    res.write(msg);
    res.end();
});

// サーバを待ち受け状態にする
// 第1引数: ポート番号
// 第2引数: IPアドレス
server.listen(config.port);
```

**/aboutにアクセス**

![スクリーンショット 2017-09-09 12.07.17.png](https://qiita-image-store.s3.amazonaws.com/0/23276/ff2ca86d-7547-518b-3517-87c35599a88b.png "スクリーンショット 2017-09-09 12.07.17.png")

**/companyにアクセス**

![スクリーンショット 2017-09-09 12.07.24.png](https://qiita-image-store.s3.amazonaws.com/0/23276/ac7f5211-56cf-7430-8d23-12e41228ec93.png "スクリーンショット 2017-09-09 12.07.24.png")

**それ以外のページにアクセス**

![スクリーンショット 2017-09-09 12.07.31.png](https://qiita-image-store.s3.amazonaws.com/0/23276/59cad340-c8f0-aef7-6280-f8f63a6fab91.png "スクリーンショット 2017-09-09 12.07.31.png")

リクエスト毎に表示させるメッセージを変える事が出来ました

## HTMLを表示してみる

HTMLを読み込む場合には、filesystemが必要になってきます。
nodeの場合、`fs`というモジュールがデフォルトで備わっているのでこれを使っていきます。

また、`ファイルの読み込み`というのは時間がかかる処理なので、[前回のノンブロッキングな処理](http://qiita.com/ritukiii/items/7f28554369d63eb373c3#%E3%83%8E%E3%83%B3%E3%83%96%E3%83%AD%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%81%AA%E5%87%A6%E7%90%86%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9)を参考に、callbackを使うようにしてみましょう。

```server.js
// nodeのコアモジュールのhttpを使う
var http = require('http');
var fs     = require('fs');
var config = require('./config');
var server = http.createServer();
var msg;

server.on('request', function(req, res) {
    // ファイルを読み込む処理は時間がかかるので、callbackにして、ノンブロッキング処理にする
    fs.readFile(__dirname + '/hello.html', 'utf-8', function (err, data) {
        // エラー発生時
        if (err) {
            res.writeHead(404, {'Content-Type' : 'text/plain'});
            res.write('page not found');
            // returnを使って、ここで処理を終了させる
            return res.end();
        }

        // 表示させるのはtextじゃなくて、htmlなので、text/htmlにする
        res.writeHead(200, {'Content-Type' : 'text/html'});
        res.write(data);
        res.end();
    });
});

// サーバを待ち受け状態にする
// 第1引数: ポート番号
// 第2引数: IPアドレス
server.listen(config.port);
```


![スクリーンショット 2017-09-09 12.16.28.png](https://qiita-image-store.s3.amazonaws.com/0/23276/7f8c35b2-289b-2e59-3775-3f7161fe83ee.png "スクリーンショット 2017-09-09 12.16.28.png")


うまく表示できました。
一応失敗してる場合も見てみたいので、読み込むファイル名をわざと間違えて`hellow.js`にしてみましょう。

![スクリーンショット 2017-09-09 12.19.37.png](https://qiita-image-store.s3.amazonaws.com/0/23276/e840d635-87a1-9465-a375-7be9f31a2bf0.png "スクリーンショット 2017-09-09 12.19.37.png")

ちゃんと`page not found`が表示されました。

## まとめ

今回出来るようになった事をまとめておきましょう。

- 外部ファイルの使うときは、exportsを使う
- リクエストURLは、`req.url`に入っているのが分かり、リクエストによって処理を分ける方法がわかった
- HTMLファイルを読み込んで表示する事が出来た
	- その場合はデフォルトモジュールの`fs`を使う
	- ファイル読み込みなどの時間のかかる処理はコールバック関数にした