JavaScriptでファイルダウンロード
JavaScriptアドベントカレンダー 14日目です。(12/19)
リンクを押すとダウンロードが勝手に始まるやつ。
どう実装していますか? 実装する機会があり私は詰まりました。
前提として、認証のあるサーバからファイルをダウンロードする想定です。
ダウンロードが始まるやーつ
anchorタグのDOMオブジェクトを作ってあげて、urlにファイルのダウンロード先を指して、click
メソッドを呼び出してあげれば実現できます。
ただしこれは認証がcookieでやられていたなら。
let anchor = document.createElement("a");
anchor.href = url;
anchor.click();
Xhrで取得してダウンロードする
認証がheaderに要素を付与して行うものだったら↑のanchor.hrefにダウンロード先をさしても認証されずに弾かれてしまいますね。
なのでxhrでheaderにトークンなりをつけて通信しましょう。
今回はfetchAPIでサンプルを書きました。
fetch("ダウンロード先", { method: 'GET', headers: new Headers([["auth-token", authToken]])}).then(response => response.blob()).then(blob => {
let anchor = document.createElement("a");
anchor.href = window.URL.createObjectURL(blob);
anchor.click();
})
ポイント
- レスポンスのbodyはBlobとして使おう
- fetchAPIなら
blob()
でできますね。 - axiosや生xhr,jqueryAjaxなら
responseType
をblob
にしてあげましょう。オプション引数なりで渡せます
- fetchAPIなら
筆者がつまってたとこ
私はライブラリxhrを使ってたところ、ダウンロードしたファイルの文字コードがサーバサイドが送ってるのと別になって唸ってました。
xhr({method: "GET",
uri: "ダウンロード先",
headers: {
"auth-token": authToken
}}, (err, response, body) => {
const blob = new Blob([ content ], { "type" : type });
let anchor = document.createElement("a");
anchor.href = window.URL.createObjectURL(blob);
anchor.click();
});
それもそのはず、ブラウザ提供のxhrの仕様ではレスポンスのデータ型はコントロールすることができ、私の使っていたライブラリxhrではデフォルトでtext
という指定になっており、JavaScriptの文字列として扱うようになってました。
JavaScriptの文字列に一度なったら文字コードはUTF-16
になってしまいダウンロードをしても意図しない文字コードとなっていました。
そこでレスポンスをblob
として扱うようにしたところ、無駄にJavaScript文字列にならなくなったので意図した文字コードでダウンロードできましたということです。