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 も早くリリースされると良いですね。

以上