HTML5 Download Attribute でファイルをダウンロードする。

Safari 10.1でa要素のdownload属性に対応することが公式に発表されましたね。

ファイルダウンロードの実装については、別タブでダウンロード用URLにアクセスし、サーバ側でファイルを作成してからレスポンスヘッダに Content-Type:application/octet-streamContent-Type:application/force-download 等を付けて返却するというのが一般的でしょうか。

この場合、別タブへの遷移によってUI/UXが損なわれたり、ファイル作成用のAPIを既存のAPIとは別に作成しなくてはならないというデメリットがあると思います。

しかし、Safariがdownload属性に対応したことで、主要なモダンブラウザでは、JavaScriptでファイルを作成しローカルにダウンロードすることが可能になりました。

サンプル

http://yug1224.github.io/example-blob-download/

ローカルのみでSJISのCSVを作ってダウンロードするものを作ってみました。

IE10以上, Chromeならそのままブラウザ標準のダウンローダーが起動します。

Safariの場合は別タブで開くだけになりますが、次期Safariの機能を試すことが出来るTechnology Preview版では、IE, Chrome同様にダウンロードが開始されます。

'use strict';

// Module読み込み
const encoding = require('encoding-japanese');
const UAParser = require('ua-parser-js');
const parser = new UAParser();
const browser = parser.getBrowser();

// テンプレート文字列
const templateStr = `
あ,い,う,え,お
か,き,く,け,こ
さ,し,す,せ,そ
た,ち,つ,て,と
な,に,ぬ,ね,の
`.trim();

/**
 * [ファイルダウンロード処理]
 */
function output() {
  // MIMEType指定
  const mimeType = 'text/css';
  // ファイル名指定
  const fileName = 'output.csv';
  // 文字コードをSJISへ変換
  const codeArray = encoding.convert(templateStr, {
    to: 'SJIS',
    from: encoding.detect(templateStr),
    type: 'ArrayBuffer'
  });
  // 8ビット符号なし整数値の配列に変換
  const uint8Array = new Uint8Array(codeArray);
  // blob作成
  const blob = new Blob([uint8Array], {type: mimeType});

  // ダウンロード
  if (window.navigator.msSaveBlob) {
    // IE
    window.navigator.msSaveBlob(blob, fileName);
  } else if (window.URL || window.webkitURL) {
    // Chrome Safari FireFox
    window.URL = window.URL || window.webkitURL;
    const url = window.URL.createObjectURL(blob);

    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;

    // Safari < 10.1 未満 の場合は _blank必須
    if (
      browser.name === 'Safari' &&
      (+browser.majar < 10 || ['10.0','10.0.1','10.0.2'].includes(browser.version))
    ) {
      a.target = '_blank';
    }

    a.click();
  } else {
    // noop
  }

  return;
}

document.getElementById('output').addEventListener('click', output);

まとめ

これで、データ自体は既存のAPIを利用してAjaxで取得し、文字コードの変換やファイル化はブラウザ上で出来るようになりました。

ほぼ2ヶ月おきにバージョンアップがされているSafariなので、10.1も早くリリースされると良いですね。

以上

HTML5JavaScript