Realize the function of JS monitoring file download completion (solve the problem of download trigger of different browsers + a tag base64url is too long to download)

Generally speaking, our js file download will use window.location.href to locate the back-end interface, the back-end generates the file and returns, and then the browser automatically downloads it. This method is the simplest, but it is impossible to get a notification of a successful download. When large files are generated and downloaded, the time is too long, and users may repeat download clicks, which will burden the server.

Therefore, you need to send a request in another way to monitor the completion of the file download. This method uses XMLHttpRequest to request, and you can monitor the completion of the file download. In addition, if you want to monitor the downloading progress bar, you can use the setting cookie loop backward This article only discusses the former method of requesting progress.

Not much bb, just start

This is the version I started with:

load = function() {
    
    
//填写你的下载时加载的提示
}
disload = function() {
    
    
//下载完成后触发,用来关闭提示框
}
getDownload = function(url) {
    
    
     load();
     var xhr = new XMLHttpRequest();
     xhr.open('GET', url, true);    // 也可用POST方式
     xhr.responseType = "blob";
     xhr.onload = function () {
    
    
         if (this.status === 200) {
    
    
             var blob = this.response;
             var reader = new FileReader();
             reader.readAsDataURL(blob);
             reader.onload = function (e) {
    
    
                 var headerName = xhr.getResponseHeader("Content-disposition");
                 var fileName = decodeURIComponent(headerName).substring(20);
                     var a = document.createElement('a');
                     a.download = fileName + ".xls";
                     a.href = e.target.result;
                     $("body").append(a);    // 修复firefox中无法触发click
                     a.click();
                     $(a).remove();
             };
             disload();
         }
     };
     xhr.send()
 };

This principle is to send a request through XMLHttpRequest and use FileReader to read the content of the file. The key is to set the a tag, convert the file content of the blob to base64 and put it into the href of the a tag, and simulate clicking to download.

But it should be noted that

  1. The download of the a tag has been tested and only works in Google and Firefox browsers, and does not trigger downloads under edge and IE
  2. If you use base64 as the url address of the a tag, you can only download files up to about 2M due to the length limitation, and the download will fail if it is higher.

first question

For browsers such as ie, there is another way to trigger the download.

 function dataURLtoBlob(dataurl) {
    
    
            var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
                bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
            while (n--) {
    
    
                u8arr[n] = bstr.charCodeAt(n);
            }
            return new Blob([u8arr], {
    
     type: mime });
        }
        
//e.target.result 正是上面代码中转换后的baseUrl,这种方法要转换为blob
var blob = dataURLtoBlob(e.target.result);
navigator.msSaveBlob(blob, fileName + ".xls");

It should be noted that navigator.msSaveBlob does not exist in browsers such as Google. Here, the first problem is solved

second question

The second question actually depends on the needs. For very small files, such as small icons, you can use base64 as the URL address. For other large files, you can store the file in the memory and point it to the virtual memory address.

var blob = dataURLtoBlob(e.target.result);
var a = document.createElement('a');
a.download = fileName + ".xls";
a.href = URL.createObjectURL(blob);
$("body").append(a);    // 修复firefox中无法触发click
a.click();
URL.revokeObjectURL(a.href);
$(a).remove();

URL.createObjectURL saves a file in the form of a blob and returns a url for download.
The URL.revokeObjectURL then the memory is freed.
At this point, the two problems have been solved. It can be seen that base64 cannot be used at all for large files, and it is best to use blob directly. Therefore, the final version can be obtained by combining:

Final version

load = function() {
    
    
//填写你的下载时加载的提示
}
disload = function() {
    
    
//下载完成后触发,用来关闭提示框
}
getDownload = function(url) {
    
    
	load();
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);    // 也可用POST方式
    xhr.responseType = "blob";
    xhr.onload = function () {
    
    
        if (this.status === 200) {
    
    
            var blob = this.response;
            if (navigator.msSaveBlob == null) {
    
    
                var a = document.createElement('a');
                var headerName = xhr.getResponseHeader("Content-disposition");
                var fileName = decodeURIComponent(headerName).substring(20);
                a.download = fileName;
                a.href = URL.createObjectURL(blob);
                $("body").append(a);    // 修复firefox中无法触发click
                a.click();
                URL.revokeObjectURL(a.href);
                $(a).remove();
            } else {
    
    
                navigator.msSaveBlob(blob, fileName);
            }
        }
        disload();
    };
    xhr.send()
};

Guess you like

Origin blog.csdn.net/qq_35530005/article/details/103381205