Node.js と TypeScript を使って簡易Webサーバー

![Node.js](http://nodejs.org/images/logos/nodejs.png "Node.js")
![TypeScript](http://www.typescriptlang.org/content/images/logo_small.png "TypeScript")

##1. 最初の Node.js プログラム…そして最初の TypeScript プログラム
Node.js と TypeScript を使って簡易Webサーバーのプログラムを作って(いじって)みた。text/plain な出力をするサーバーで 80 番のポートでリクエストを受け付ける。以下のコードが最初のプログラムである。英語("Hello World")の出力は問題ない。

```ts:server.ts(最初のNode.jsプログラム)
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/plain'
    });
    res.end("Hello World");
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
```
![2014-0510-2325.png](https://qiita-image-store.s3.amazonaws.com/0/32879/369b83ba-de7a-5f6e-42eb-d0b8befed4c0.png)

##2. 日本語表示プログラム(のはずが)
「Hello World」の表示の後ろに「こんにちは世界」をくっつけてみた。
ブラウザの表示をみると日本語(「こんにちは世界」)は文字化けしてしまった。

```ts:server.ts
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/plain'
    });
    res.end("Hello World こんにちは世界");
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
```

![2014-0510-2321.png](https://qiita-image-store.s3.amazonaws.com/0/32879/181d36ef-d74f-de2c-a0f9-37393d8ebd5b.png)
↑日本語が文字化けしている。

##3. 日本語表示に成功
Content-Type に 'text/plain; charset=utf-8' のように文字コード(utf-8)を指定することで文字化けの問題が解消した。

```ts:server.ts
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8'
    });
    res.end("Hello World こんにちは世界");
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
```
![2014-0510-2318.png](https://qiita-image-store.s3.amazonaws.com/0/32879/da035fae-626d-0dc9-8646-3948ddde7ffb.png)
↑文字化けが直った。

##4. 新たな問題が
アクセスするたびに全く同じ出力(「Hello World こんにちは世界」)を出しているので、呼び出された回数と時刻を表示してみようと思ってコードを追加した。
すると、コンソール出力に予期せぬ結果がでた。ブラウザで1回アクセスするとサーバー処理が2回呼び出されていることが分かった。


```ts:server.ts
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    count++;
    console.log(count);
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8'
    });
    res.end("Hello World こんにちは世界 (" + count + "回アクセス) " + new Date());
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
1
2
```

![2014-0510-2338.png](https://qiita-image-store.s3.amazonaws.com/0/32879/566e7bcc-a142-da77-cf15-286af7873851.png)
↑ブラウザでは「1回アクセス」と表示されているが、コンソール出力ではサーバーの処理が2回呼び出されていることが分かる。

##5. 複数回呼び出しの問題を調査する

キャッシュに絡む問題かなと思い、レスポンスヘッダに Cache-Control: no-cache をつける。
それと同時に、リクエストのメソッドとURLをアクセスカウンタと同時に出力させるようにした。
コンソール出力を見て原因(理由)が判明。ブラウザから favicon.ico(※) へのアクセスが行われていたのである。

※ Faviconとは、Webブラウザのブックマーク(お気に入り)機能で表示される、そのWebサイトのアイコン画像。
　“favorite icon”の略で、一般的には16×16ピクセルのWindowsビットマップファイル(ICO形式)が用いられる。

```ts:server.ts
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    count++;
    console.log(count + " " + req.method + " " + req.url);
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8',
        'Cache-Control': 'no-cache'
    });
    res.end("Hello World こんにちは世界 (" + count + "回アクセス) " + new Date());
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
1 GET /
2 GET /favicon.ico
3 GET /
4 GET /favicon.ico
5 GET /
6 GET /favicon.ico
7 GET /
8 GET /favicon.ico
```

##6. 簡易Webサーバー完成？
アクセスされたURLがルート(/)でなければ「HTTP 404」を返すように修正を加えた。
日本語も文字化けしないし、favicon.ico へのアクセスも一回404で弾いてあげるとそれ以降発生しないようだ。

```ts:server.ts(最終版)
import http = require('http');

console.log("program start");

var count: number = 0;
http.createServer(function (req, res) {
    count++;
    console.log(count + " " + req.method + " " + req.url);
    if (req.url != '/') {
        res.writeHead(404, {
            'Content-Type': 'text/plain; charset=utf-8',
        });
        res.end("Not Found.");
        return;
    }
    res.writeHead(200, {
        'Content-Type': 'text/plain; charset=utf-8',
        'Cache-Control': 'no-cache'
    });
    res.end("Hello World こんにちは世界 (" + count + "回アクセス) " + new Date());
}).listen(80, "127.0.0.1");

console.log("program end");
```

```text:コンソール出力
program start
program end
1 GET /
2 GET /favicon.ico
3 GET /
4 GET /
5 GET /
6 GET /
7 GET /
8 GET /
```

##7. 最後に(Node.js と TypeScript の今後)

Node.js の API を使ったサーバー開発を体験してみて、汎用の Web サーバーとして仕上げるのは困難かもしれないが、用途を限定した Web サーバーに応用することは割りと簡単にできそうだと思った。
Visual Studio 向けの Node.js アプリ開発環境([Node.js Tools for Visual Studio](https://nodejstools.codeplex.com/))のベータ版が提供された。Node.js のアプリをTypeScript を用いて開発するための支援環境である。
今のところ対話的デバッグ環境の動作確認ができてないがそれを抜きにしてもアプリケーション開発の効率は上がった。
Node.js と TypeScript の今後の展開が楽しみである。

![2014-0511-0035.png](https://qiita-image-store.s3.amazonaws.com/0/32879/8e0485a8-7b06-3af8-bcba-8273e487311d.png)
↑TypeScript を用いるプロジェクトテンプレート。Webブラウザアプリから Node.js を使ったサーバーアプリまで揃っている。Node.js ではコンソールアプリの開発もできる。

![2014-0511-0039.png](https://qiita-image-store.s3.amazonaws.com/0/32879/5ebb0768-f08d-96f9-f657-90f71a5c2edb.png)
↑TypeScript のソースコード上でブレークポイントを設定してデバッグできる。

![2014-0511-0422.png](https://qiita-image-store.s3.amazonaws.com/0/32879/e6fbb922-774b-3a9d-ddc1-0875161e10e2.png)
↑標準ライブラリを利用する部分で[インテリセンス](http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%86%E3%83%AA%E3%82%BB%E3%83%B3%E3%82%B9)([オートコンプリート](http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%BC%E3%83%88%E3%82%B3%E3%83%B3%E3%83%97%E3%83%AA%E3%83%BC%E3%83%88))が使えるのでコーディングがはかどる。TypeScript の醍醐味である。