HTML
JavaScript
HTML5

JavaScriptでファイルダウンロード

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ならresponseTypeblobにしてあげましょう。オプション引数なりで渡せます

筆者がつまってたとこ

私はライブラリ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文字列にならなくなったので意図した文字コードでダウンロードできましたということです。