【问题标题】:Large file downloads via ajax call give "Network Error" in Chrome browser通过 ajax 调用下载大文件在 Chrome 浏览器中出现“网络错误”
【发布时间】:2019-03-03 11:41:33
【问题描述】:

所以我正在尝试下载一个对我的 api 进行 ajax 调用的 zip 文件。该 api 以一个 base 64 编码的字节数组响应。现在对于大多数下载来说,这工作得很好,但是当 zip 文件变得太大时,它开始在 Chrome 中失败。在所有其他浏览器中都能正常工作。从我在堆栈溢出中发现的内容来看,这是 chrome 中的一个已知问题,人们建议使用 blob。事情是我正在使用 blob 并且仍然有问题。这是我处理下载的代码。我通过为 contentType 传递不同的值来使用它来下载 pdf 和 zip 文件。有没有人遇到过这个问题?是否有任何解决方法或脚本可以添加到页面来解决这个问题?

// 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);
        }
}

【问题讨论】:

  • 即使您克服了所有问题,谷歌浏览器也有自己的网络超时,很遗憾您无法更改它。检查这个superuser.com/questions/633648/…
  • 它实际上不是超时错误,chromes 错误消息只是让它看起来那样。 Api 的响应速度足够快,它只是特定于 chrome 如何以这种方式处理下载
  • @victor 你能看看我下面的答案,让我知道它是否有效吗?在此先感谢...
  • @victor 面临完全相同的问题,有没有适合您的解决方案?

标签: javascript ajax google-chrome


【解决方案1】:

api 以 base 64 编码字节数组响应

为什么?我建议您添加一种方法,该方法将使用纯二进制 zip 文件进行响应。

当设置 xhr.responseType = "blob"; 并像在 Chrome 中一样保存它。

如果你想让你的 api 保持原样,请尝试摆脱 Array 并直接填写 Uint8Array。

UPD。我在具有 16GB RAM 的 Ubuntu 18.04 下的 Chrome 69 上对此进行了测试,我发现 Chrome 不会让我以这种方式下载超过 1000 兆字节的数据。

您要下载的文件有多大?

自行检查(不要忘记确保没有任何东西会阻止下载):

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>

【讨论】:

  • 是的,我喜欢保持 api 的原样,因为它可以在所有其他浏览器中工作。我会试试 Uint8Array
  • 因此 zip 文件的大小可能会根据某些特定于应用程序的详细信息而有所不同。它可能小至 10mb,而在其他情况下则大于 1gb。在这个问题出现之前,它的容量超过 1gb 是非常罕见的。
  • 这解决了我的问题,我确实必须使用 vanilla js XHR 对象,因为 jquery ajax 调用存在 blob 类型的问题。
【解决方案2】:

似乎是一个错误。在解决此问题的同时,您可以执行以下操作。

将文件拆分成更小的部分,并发出许多 ajax 请求,然后在下载完所有内容后,通过连接这些部分来重建原始文件客户端。从那里照常进行。

【讨论】:

    【解决方案3】:

    大型 blob 下载的问题主要与内存泄漏有关。 我认为一些额外的代码可以解决这个问题。

    1. 您的 blob 存储在内存中,如果它非常大则不好, 因为浏览器进程有可用内存的限制。这个可以 解决 indexedDB indexeddb example,你应该添加一个 blob 到 indexedDB,然后立即从中删除。当你写 blob 到 indexeddb,浏览器在文件系统中创建缓存文件,并从 此时,您的 blob 将存储在文件系统中,例如 File。 而这个动作会释放大量内存。

    2. 创建时 ObjectUrl,您将在内存中有一个额外的 blob 链接,并且 垃圾收集器将仅在文档卸载事件时将其删除。所以 你需要撤销ObjectURL。

    var previousBlob = null;
    
    downloadFile(source, filename) {
       if(previousBlob){
         URL.revokeObjectURL(previousBlob);
         previousBlob = null;
       }
       //.. do stuff
    }
    

    附言

    IndexedDB 帮助我解决了 Chrome 的一个错误。在 Chrome 浏览器中,您无法创建 1000 个 blob(总共在所有打开的选项卡中),所以我通过将 blob 写入 indexeddb 来解决这个问题。因为blobs 变成了一个文件,并且 blobs 的限制不会散布在它上面。你可以在firefox的“about:memory”工具上看到你自己的结果,是最好的内存分析工具(比其他浏览器更好)

    【讨论】:

      【解决方案4】:

      除了以上这些解决方法,你还可以尝试在web.config中设置maxRequestLength属性。

      <system.web>
          ...
          <httpRuntime targetFramework="4.5.1" maxRequestLength="51200" executionTimeout="30" />
          <!-- for 50 MB set maxRequestLength="51200"-->
      </system.web>
      

      希望这会有所帮助...

      【讨论】:

        猜你喜欢
        • 2013-02-24
        • 2017-02-21
        • 2012-12-21
        • 1970-01-01
        • 2011-05-20
        • 1970-01-01
        • 2015-09-16
        • 1970-01-01
        • 2021-04-09
        相关资源
        最近更新 更多