前提・実現したいこと
JSでファイルのダウンロード処理を実装しており、
その処理は下記のように動作しています。
- ユーザが画面上のダウンロードボタンをクリック(非同期でファイルデータ取得APIリクエストを行う)
- ファイルの保存ダイアログが開く
- ユーザがダイアログの「保存」ボタンをクリック
- ブラウザのダウンロードバーに保存されたファイルが表示される
ダウンロード対象のファイルは取得用APIが存在し、レスポンスとしてファイルのバイナリデータを返します。
しかしサイズの大きいファイルをダウンロードしようとしたところ、
上記1.と2.の間(APIレスポンスの取得が完了するまでの間)、ブラウザ上に何も表示されないため
「ユーザビリティが悪い。よくあるダウンロード処理のようにボタンを押したらすぐにブラウザ標準機能のダウンロードバーを表示し、
ダウンロードの進行状況が分かるようにしてほしい(下記イメージ)」との指摘を受けました。
■図1
Chrome標準のダウンロードバーで進行状況が表示される事
※これは参考画像であり、私が作成しているサイトの画像ではありません
実現したいこと
下記のような流れになるのが理想的です。
- ユーザが画面上のダウンロードボタンをクリック(非同期でファイルデータ取得APIリクエストを行う)
- ファイルの保存ダイアログが開く
- ユーザがダイアログの「保存」ボタンをクリック
- ブラウザのダウンロードバーが表示される(■図1参照)…ここでユーザはダウンロードの進行状況が分かる
- ダウンロード完了後、ダウンロードバーから保存されたファイルを開ける
別途プログレスバーなどを実装するのではなく、
JSだけで、このような事が可能なのかを知りたいです。
発生している問題
下記のような実装を行っていますが、
この状態では、一旦バイナリデータを全て受け取ってからwindow.URL.createObjectURL
でオブジェクトを作成し、
ダウンロードさせているため、進行中の表示を行うことが出来ません。
他の実装方法があるのかと調べてみましたが、恥ずかしながら見つけることができませんでした。
もしこちらの要望を満たす方法をご存じの方がいらっしゃいましたら、ご教示頂けますようお願い致します。
ソース
JavaScript
1function downloadFile(method, url) { 2 const xhr = new XMLHttpRequest(); 3 4 //レスポンス取得時 5 xhr.onload = function (e) { 6 const res = xhr.response; 7 8 if (xhr.status != 200) { 9 //ステータスが200以外の場合(省略) 10 return; 11 } 12 13 if (res.type !== 'application/octet-stream') { 14 //レスポンスがバイナリ以外の場合(省略) 15 return; 16 } 17 18 //レスポンスヘッダからファイル名を取得する 19 const disposition = xhr.getResponseHeader('Content-Disposition'); 20 if (disposition && disposition.indexOf('attachment') !== -1) { 21 const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; 22 const matches = filenameRegex.exec(disposition); 23 if (matches != null && matches[1]) { 24 fileName = matches[1].replace(/['"]/g, ''); 25 } 26 } 27 28 //ブラウザごとのダウンロード処理 29 if (window.navigator.msSaveBlob) { 30 // for IE 31 window.navigator.msSaveBlob(res, fileName); 32 } else if (window.URL && window.URL.createObjectURL) { 33 // for Chrome & Firefox 34 const link = document.createElement('a'); 35 link.href = window.URL.createObjectURL(res); 36 link.download = decodeURI(fileName); 37 link.click(); 38 } 39 }; 40 41 //レスポンス受信の失敗時 42 xhr.onerror = function (e) { 43 //省略 44 }; 45 46 //タイムアウト時 47 xhr.ontimeout = function (e) { 48 //省略 49 } 50 51 //処理のキャンセル時 52 xhr.onabort = function (e) { 53 //省略 54 } 55 56 xhr.open(method, url, true); 57 xhr.setRequestHeader("X-Authorization", "認証情報"); 58 xhr.setRequestHeader("Content-Type", "application/json"); 59 xhr.responseType = "blob"; 60 xhr.timeout = 10000; 61 xhr.send(null); 62}
環境
JQuery 3.2.1
Chrome 78.0.3904.97
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/02/14 08:15