Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large file downloads via ajax call give "Network Error" in Chrome browser

So I am trying to download a zip file with an ajax call to my api. The api responds with a base 64 encoded byte array. Now for most of the downloads this is working just fine, but when the zip file gets too large it starts to fail in Chrome. Works fine in all other browsers. From what I have found on stack overflow this is a known issue in chrome, and people suggested using blobs. Thing is I am using blobs and still have the issue. Here is my code for handling the download. I use this to download pdf and zip files by passing in different values for contentType. Has anyone run into this issue before? Are there any work arounds or scripts I can add to the page that will remedy this problem?

// data is base 64 encoded byte array
function download(data, filename, contentType) {

    var byteCharacters = atob(data);
    var byteNumbers = new Array(byteCharacters.length);
    for (var i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
    }
    var byteArray = new Uint8Array(byteNumbers);
    var blob = new Blob([byteArray], { type: contentType });

    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        // IE / edge workaround
        window.navigator.msSaveOrOpenBlob(blob, filename);
    } else if (navigator.userAgent.indexOf("Firefox") > 0) {
        var a = window.document.createElement('a');
        a.download = filename;
        a.style.cssText = "display: none";
        a.target = "_blank";
        // Append anchor to body.
        document.body.appendChild(a);
        a.href = "data:" + contentType + ";base64," + data;
        a.click();

        // Remove anchor from body
        document.body.removeChild(a);
    } else //Chrome, safari, etc
        {
            var a = document.createElement("a");
            a.style = "display: none";
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
        }
}
like image 354
victor Avatar asked Sep 27 '18 14:09

victor


People also ask

Why do files fail to download?

This error means that your computer's security settings blocked the file. Learn more about blocked downloads. On Windows: Windows Attachment Manager could have removed the file you tried to download. To see what files you can download or why your file was blocked, check your Windows internet security settings.


1 Answers

The api responds with a base 64 encoded byte array

Why? I'm suggesting you to add a method which will respond with pure binary zip files.

When set xhr.responseType = "blob"; and just save it like you do it for Chrome.

If you want to keep your api as is, try to get rid of Array and fill in Uint8Array straightway.

UPD. I tested this on my Chrome 69 under Ubuntu 18.04 with 16gb RAM and I found that Chrome would not let me download much more than 1000 megabytes this way.

How large are file you are trying to download?

Check it by yourself (don't forget to make sure that nothing will block downloading):

function getBlob(size) {
    let u8a = new Uint8Array(size);
    for (var i = 0; i < size; i++) {
        u8a[i] = 33 + Math.floor(Math.random() * 5)
    }
    return new Blob([u8a]);
}

function downloadFile(source, filename) {
	if (source instanceof (File, Blob)) {
		filename = source.name || filename;
		source = URL.createObjectURL(source);
	}
	let link = document.createElement("a");
	link.style.display = "none";
	link.href = source;
	link.download = filename || "blob.bin";

	document.body.appendChild(link);

	link.click();

	setTimeout(function () {
		document.body.removeChild(link);

		URL.revokeObjectURL(source);
	}, 3000);
}
Size (MB): <input id="in" type=number min=1 max=3000>
<button onclick="downloadFile(getBlob(1024*1024*(+document.getElementById('in').value)))">download</button>
like image 89
WitcherGeralt Avatar answered Oct 07 '22 06:10

WitcherGeralt