AngularJS の $locationProvider.html5Mode について

AngularJS で構築するアプリケーションで $locationProvider.html5Mode をどう設定するか小一時間悩んだ結果をまとめてみました。

導入
------------------------------------------
AngularJS では $routeProvider を使用してクライアントサイドでのルーティングが可能です。

```javascript
angular.module('app').config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/aaa/', {controller: 'AaaController', templateUrl: 'aaa.html'})
    .when('/bbb/', {controller: 'BbbController', templateUrl: 'bbb.html'});
}]);
```

こんなカンジで指定することでURLに応じて Controller と View が変更されるようになります。便利だね！

ところで、このURLですが標準ではこんなカンジになります。

```
http://www.example.com/#/aaa/
```

これは **Hashbang Mode** と呼ばれ、ハッシュ(#)以降の部分をアプリケーションのパスとして利用するモードです。
ちなみに Hashbang とは "#!" のことで、一昔前に Ajax を多用したサイトでURLによく使われていました（なぜ多用され、現在廃れつつあるのかは "Hashbang URL" とかでググりましょう）。

AngularJS の標準では "!" つまりbang部分がないのでなんだかちょっと違和感があります。
ちなみに hashPrefix という設定をすることで正当な(?) Hashbang にすることもできます。

```javascript
angular.module('app').config(['$locationProvider', function($locationProvider) {
  $locationProvider.hashPrefix('!');
}]);
```


本題
------------------------------------------
前述の Hashbang を利用したURLは現在では「あまり使うべきではない」と言われています。
また HTML5 で pushState という機能が採用され Hashbang を使わずともブラウザヒストリを記録しつつクライアントサイドで画面を書き換えることができるようになりました。

AngularJS では $locationProvider.html5Mode を変更することで Hashbang Mode から HTML5 Mode に変更することができます。

```javascript
angular.module('app').config(['$locationProvider', function($locationProvider) {
  $locationProvider.html5Mode(true);
}]);
```

Hashbang Mode と HTML5 Mode それぞれでURLは次のようになります。

```
# Hashbang Mode
http://www.example.com/#/aaa/
# HTML5 Mode
http://www.example.com/aaa/
```

ただし pushState に対応していない IE9 などのブラウザもまだまだ現役です。
AngularJS ではそういった pushState 未対応ブラウザの場合は自動で Hashbang Mode にフォールバックしてくれます。超便利だね！


Hashbang Mode と HTML5 Mode の違い
------------------------------------------
先述の通り Hashbang を使用したURLは廃れつつあります。……が、HTML5 Mode も万能というわけではありません。

先ほどのように HTML5 Mode を使うと http://www.example.com/aaa/ の様にURLにハッシュが含まれなくなります。
その結果、Hashbang Mode と HTML5 Mode で次のような違いが現れてしまいます。

```
# Hashbang Mode
http://www.example.com/#/aaa/ -> WEBサーバー www.example.com の / にリクエストが飛ぶ
# HTML5 Mode
http://www.example.com/aaa/ -> WEBサーバー www.example.com の /aaa/ にリクエストが飛ぶ
```

つまり次の通り。

- Hashbang Mode ではクライアントサイドでページを生成すればOK。
- HTML5 Mode ではサーバー側で /aaa/ に対応するページを生成する必要がある。所謂 pjax にサーバー側で対応しなくてはならない。

場合によっては後者はとても面倒です。


Hashbang URL の問題点とは？
------------------------------------------
ところで Hashbang を使うべきではない理由とはなんでしょうか。[参考サイト](http://d.hatena.ne.jp/karasuyamatengu/20110212/1297465199)によればざっくり次のようなカンジです。

- GoogleBot 以外の Hashbang に対応していないクローラー、ボットなどがコンテンツにアクセスできなくなる
- ブラウザ外のキャッシュができなくなる
- Microformats が使い難くなる
- Facebook の Like widgets などが難しくなる
- Referer にページレベルの情報が無くなる
- JavaScript にエラーがあるとなにも表示されない
    - arrayの終りに,が残っているだけでIE利用者には真っ白な画面しかみえなくなる
    - 開発者が console.log を間違えて残してしまうとほとんどのユーザー（IE利用者）が真っ白な画面を見ることになる
    - サイト管理者のコントロール下にない広告のJavaScriptにエラーがあるとコンテンツが見れなくなる


結論：どちらのモードを使うべきか
------------------------------------------
先ほどの参考サイトにもほぼ同じ事が書いてありますが、次のように考えることができると思います。

- 商品ページなどSEO等が重要になる所謂「コンテンツ」の場合は積極的に HTML5 Mode を採用するべき。
- 管理画面や、フォームなどコンテンツというよりは「アプリケーション」と呼ぶべきページの場合は場合によって Hashbang Mode の採用を検討する。
    - ただし、一般に公開されるお問い合わせフォームなどで、外部の広告用スクリプトなどを利用する場合は細心の注意を払う（できるなら HTML5 Mode）を使う。

以上。

参考
------------------------------------------
- [AngularJS: Using $location](http://docs.angularjs.org/guide/dev_guide.services.$location)
- [さらなる「#!」URL批判 - karasuyamatenguの日記](http://d.hatena.ne.jp/karasuyamatengu/20110212/1297465199)