在谷歌浏览器上下载大文件(最大 15 mb)时出现问题

Posted

技术标签:

【中文标题】在谷歌浏览器上下载大文件(最大 15 mb)时出现问题【英文标题】:Problems downloading big file(max 15 mb) on google chrome 【发布时间】:2016-12-11 10:34:05 【问题描述】:

我在 Google Chrome 中遇到下载问题。 我正在使用 Ruby 2.2、Rails 4.2、AngularJS 1.2。

我们这里没有数据库。我们通过 API 获得的一切。我们尝试下载的文件大约是 7 mb。它给了我们“失败:网络错误”。虽然它在 Firefox 上运行良好。

我们从 API 获取 JSON 格式的二进制数据。我们正在解析它。然后:

send_data response_fields["attachment"], type: response_fields["mimeType"], disposition: 'attachment', filename: params[:filename]

当我们使用 AngularJS 时,我们在 AngularJS 控制器中捕获该值,然后将其转换为:

var str = data;
var uri = "data:" + mimeType + ";base64," + str;

var downloadLink = document.createElement("a");
downloadLink.href = uri;
downloadLink.download = filename;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);

这适用于 Firefox 甚至 Chrome 以减小文件大小。不知道为什么它会在 Chrome 上显示更大尺寸的错误。

有什么建议吗?

谢谢。

【问题讨论】:

尝试使用 blob 代替 base64 我遇到同样的错误:下载失败-网络错误 【参考方案1】:

这几乎是1 和2 这些问题的重复,但由于它们确实专门处理画布元素,我将在这里重写一个更全局的解决方案。

这个问题是由于 chrome 在锚点 (<a>) download 属性中设置的大小限制。我不太确定他们为什么这样做,但解决方案很简单。

将您的 dataURI 转换为 Blob,然后从此 Blob 创建一个 ObjectURL,并将此 ObjectURL 作为锚点的下载属性传递。

// edited from https://developer.mozilla.org/en-US/docs/Web/API/htmlCanvasElement/toBlob#Polyfill
function dataURIToBlob(dataURI) 

  var binStr = atob(dataURI.split(',')[1]),
    len = binStr.length,
    arr = new Uint8Array(len),
    mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

  for (var i = 0; i < len; i++) 
    arr[i] = binStr.charCodeAt(i);
  

  return new Blob([arr], 
    type: mimeString
  );



var dataURI_DL = function() 

  var dataURI = this.result;
  var blob = dataURIToBlob(dataURI);
  var url = URL.createObjectURL(blob);
  var blobAnchor = document.getElementById('blob');
  var dataURIAnchor = document.getElementById('dataURI');
  blobAnchor.download = dataURIAnchor.download = 'yourFile.mp4';
  blobAnchor.href = url;
  dataURIAnchor.href = dataURI;
  stat_.textContent = '';

  blobAnchor.onclick = function() 
    requestAnimationFrame(function() 
      URL.revokeObjectURL(url);
    )
  ;
;

// That may seem stupid, but for the sake of the example, we'll first convert a blob to a dataURI...
var start = function() 

  stat_.textContent = 'Please wait while loading...';
  var xhr = new XMLHttpRequest();
  xhr.responseType = 'blob';
  xhr.onload = function() 
    status.textContent = 'converting';
    var fr = new FileReader();
    fr.onload = dataURI_DL;
    fr.readAsDataURL(this.response);
  ;
  xhr.open('GET', 'https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4?dl=0');
  xhr.send();

  confirm_btn.parentNode.removeChild(confirm_btn);
;

confirm_btn.onclick = start;
<button id="confirm_btn">Start the loading of this 45Mb video</button>
<span id="stat_"></span>
<br>
<a id="blob">blob</a>
<a id="dataURI">dataURI</a>

还有一个用于 FF 的 jsfiddle version,因为它们不允许来自 stack-sn-ps 的 downloadattribute...

【讨论】:

遗憾的是 chrome 将 URI 限制为 2MB ***.com/a/41755526/704008。将 blob 用于大尺寸的绝佳解决方法。 FF & chrome Fiddle 有什么区别?好像一样 @PranavSingh,是的,它们是相同的(IIRC)。只是FF用download属性和stacksn-ps做了一些奇怪的事情(在我的身上,它没有显示下载弹出窗口,并用blob的名称保存,没有扩展名)但它实际上似乎在FF 52上修复了跨度> @PranavSingh,你的意思不是在 jsfiddle 上也不是在你自己的页面上?这听起来像是开发版中的一个错误。无论如何,不​​要更改返回的 blobURI。仅应使用download 属性来设置文件名。对于更大的浏览器支持,您可能需要使用 FileSaver.js 库。您只需向它提供生成的 blob 和文件名,它将解决不同实现中的许多怪癖。 (也适用于我的 54 nightly,我没有开发版) @Kaiido 我的意思是我有一个休息 API(POST),它可以动态创建和流式传输 zip 到客户端。如何在客户端/浏览器端使用它?我已经使用表单提交单击完成了此操作,但是对于非常大的文件,它会在一段时间后使网络失败。此外,这在服务器位于本地时工作正常,但在部署在 google k8s 上时会出现网络失败错误。在过去的 18-20 天里,我一直坚持这一点。

以上是关于在谷歌浏览器上下载大文件(最大 15 mb)时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MATLAB 中加载大文件(~150MB)?

谷歌浏览器点新链接时出现:此文件可能会损坏你的计算机。是啥问题?

使用EXCEL vba下载文件时出现问题

怎么解决使用python的requests获得网页时出现sslEOFError错误

PHP:使用 ZipArchive 创建 zip 文件时出现错误 (500)

运行我的应用程序时出现 Angular2 GZIP 问题