JavaScriptでファイルダウンロード処理を実現する

# はじめに

モダンブラウザならJavaScriptでファイルダウンロード処理を実現することができます。SPA(シングルページアプリケーション)など、クライアント側にデータを持つようなアプリケーションであればサーバアクセスなしにメモリの内容からファイルを生成してダウンロードさせることができます。

# 実装方法

やり方は

1. リンクの[HTML5のdownload属性](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#Attributes)を使用してダウンロードファイル名を設定 
1. [File APIのBlob](https://developer.mozilla.org/ja/docs/Web/API/Blob)を使用してデータを作成
1. `window.URL.createObjectURL`でBlobからURLを生成しそれをリンク先に設定

とするだけです。これでChromeとFireFoxはいけます([download属性のブラウザ実装状況を見ると](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#Browser_compatibility)を見ると、試せていないですがEdgeとOperaもいけそう)。加えてIEをサポートする場合は、IE10/11であれば`window.navigator.msSaveBlob(またはmsSaveOrOpenBlob)`を使うことで同様のことができます(IE9以下はBlobが使えないため対応できません)。Safariに関してはまた別の方法で対応することができるようで、[saveAsのpolyfillであるFileSaver.js](https://github.com/eligrey/FileSaver.js)では[Safariにも対応している模様](https://github.com/eligrey/FileSaver.js#supported-browsers)。[実装はこのあたり](
https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js#L98-L109)。

# サンプルコード
下記はChrome/FireFox/IE11で動作確認したサンプルコードになります。「ダウンロード」リンクをクリックすると「あいうえお」と書かれたテキストファイル(test.txt)がダウンロードされます。

```html:ダウンロードサンプル
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Download Sample</title>
    </head>
    <body>
        <script type='text/javascript'>
            function handleDownload() {
                var content = 'あいうえお';
                var blob = new Blob([ content ], { "type" : "text/plain" });
                        
                if (window.navigator.msSaveBlob) { 
                    window.navigator.msSaveBlob(blob, "test.txt"); 
                    
                    // msSaveOrOpenBlobの場合はファイルを保存せずに開ける
                    window.navigator.msSaveOrOpenBlob(blob, "test.txt"); 
                } else {
                    document.getElementById("download").href = window.URL.createObjectURL(blob);
                }
            }
        </script>
        <a id="download" href="#" download="test.txt" onclick="handleDownload()">ダウンロード</a>
    </body>
</html>
```

# おまけ: 日本語を含むCSVファイルのダウンロード
ファイルダウンロード処理でよくありがちなCSVファイルのダウンロードを本方式で行うと、UTF-8のためそのままではExcelでは開けないという問題があります。実はExcelはBOM付きにするとUTF-8で開くことができますので、BOMを付与してダウンロードさせればOK。以下、CSVファイルダウンロードのサンプルコードです。

```html:CSVダウンロードサンプル
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Download Sample</title>
    </head>
    <body>
        <script type='text/javascript'>
            function handleDownload() {
                var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
                var content = 'あいうえお,かきくけこ,さしすせそ';
                var blob = new Blob([ bom, content ], { "type" : "text/csv" });
                        
                if (window.navigator.msSaveBlob) { 
                    window.navigator.msSaveBlob(blob, "test.csv"); 
                    
                    // msSaveOrOpenBlobの場合はファイルを保存せずに開ける
                    window.navigator.msSaveOrOpenBlob(blob, "test.csv"); 
                } else {
                    document.getElementById("download").href = window.URL.createObjectURL(blob);
                }
            }
        </script>
        <a id="download" href="#" download="test.csv" onclick="handleDownload()">ダウンロード</a>
    </body>
</html>
```

これでExcel好きな人にも大丈夫ですね！！

# 参考サイト
* [File API で作成した Blob をダウンロードする](https://hebikuzure.wordpress.com/2012/12/16/file-api-%E3%81%A7%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F-blob-%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E3%81%99%E3%82%8B/)