Chrome 65 阻止跨源<a download>。强制下载的客户端解决方法?

IT技术 javascript google-chrome frontend tampermonkey
2021-01-19 23:38:11

Chrome 65 移除了对具有 cross-origin s 的锚元素上download属性的支持href

阻止跨域 <a 下载>

为了避免本质上是用户介导的跨源信息泄漏,Blink 现在将忽略具有跨源属性的锚元素上的下载属性的存在。请注意,这既适用于HTMLAnchorElement.download元素本身,也适用于元素本身。

意图删除| Chromestatus 跟踪器| 铬虫

这会破坏无服务器下载(对于跨源资源)。它还破坏了 Reddit Enhancement Suite 的保存图像按钮 ( .res-media-controls-download) RES v5.12.0通过使用chrome.downloads API修复了这个问题(扩展现在请求您的管理下载权限

任何解决方法?

Web 规范中的更多详细信息,感谢@jbmilgrom

2个回答

根据讨论 blob:data:URL 不受影响,因此这里是使用fetchBlob的解决方法

客户端强制下载媒体

function forceDownload(blob, filename) {
  var a = document.createElement('a');
  a.download = filename;
  a.href = blob;
  // For Firefox https://stackoverflow.com/a/32226068
  document.body.appendChild(a);
  a.click();
  a.remove();
}

// Current blob size limit is around 500MB for browsers
function downloadResource(url, filename) {
  if (!filename) filename = url.split('\\').pop().split('/').pop();
  fetch(url, {
      headers: new Headers({
        'Origin': location.origin
      }),
      mode: 'cors'
    })
    .then(response => response.blob())
    .then(blob => {
      let blobUrl = window.URL.createObjectURL(blob);
      forceDownload(blobUrl, filename);
    })
    .catch(e => console.error(e));
}

downloadResource('https://giant.gfycat.com/RemoteBlandBlackrussianterrier.webm');

但是,fetch 仅适用于某些 URL。您可能会收到 CORS 错误:

Failed to load https://i.redd.it/l53mxu6n14o01.jpg: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://redditp.com' is therefore not allowed access.

有一些扩展程序可让您拦截和修改或删除网站的安全标头:

ModHeader - Chrome 网上应用店

(但设置Access-Control-Allow-Origin: *对我来说破坏了 YouTube)

表现

请注意,这种方法的性能不是很好!有时我的下载会停滞 <1 分钟。不过,页面的其余部分在这段时间内是响应式的。我没有研究过这个,但我认为创建大型 Blob 是资源密集型的。

暴力猴子 / 篡改猴子

如果您的用例是用户脚本,则有 GM_download(options), GM_download(url, name)

⚠ 在 Tampermonkey 中这是一个测试版功能,您必须首先Tampermonkey Dashboard > Settings 中设置下载模式: [Browser API ▾]

Tampermonkey 仪表板 > 设置 > 下载

想知道如果文件大小超过 500MB 怎么办?我有哪些选择?我需要使用 StreamSaver.js 吗?我的其他选择是什么?谢谢!
2021-03-17 23:38:11
@nfdavenport 抱歉,我忘了,在 Firefox 中,您必须将元素添加到 DOM 中才能访问a.click() stackoverflow.com/a/32226068似乎可行,也许这就是全部。
2021-03-19 23:38:11
我知道这个问题是关于 chrome 的,但是在让它在 chrome 中很好地工作之后,它在 Firefox 或 MS 浏览器中不起作用。
2021-03-26 23:38:11
@Leeroy 谢谢你为 Firefox 和 Edge 工作。我不想为 IE11 填充我的应用程序来获取工作,但如果我有 IE11 可能也能工作。我收到了“ReferenceError: 'fetch' is undefined”,但由于这是一个新项目,我将尝试支持 IE11。:)
2021-04-05 23:38:11
根据我的经验,在提示用户保存位置之前下载了整个文件。有没有办法让这个功能更像一个普通的下载,用户可以实时查看进度并预先选择保存位置?
2021-04-05 23:38:11

显然,Web 规范在某些时候更改为禁止跨域下载。content-disposition: attachment在响应中添加标头,跨域下载可能会再次工作。

nginx的例子: add_header Content-Disposition "attachment;";
2021-03-17 23:38:11
@LiranH 你有没有想过解决办法?
2021-03-20 23:38:11
@Anthony 怕不是
2021-03-21 23:38:11
这确实对我有用,但产生了一个新问题:其srcurl 具有上述响应标头的iframe现在出现意外行为:它们会在渲染后立即自动下载 src 文件,而且它们的内容是空白的。
2021-03-31 23:38:11
@LiranH 如果请求来自某个域而不是另一个域,我正在研究有条件地设置标头。nginx 似乎很棘手,也许还有另一种方法可以做到这一点。
2021-04-06 23:38:11