Chrome 65 阻止跨域 <a 下载>。强制下载的客户端解决方法?
Posted
技术标签:
【中文标题】Chrome 65 阻止跨域 <a 下载>。强制下载的客户端解决方法?【英文标题】:Chrome 65 blocks cross-origin <a download>. Client-side workaround to force download? 【发布时间】:2018-09-03 14:42:40 【问题描述】:Chrome 65 移除了对download
属性的支持在具有跨域href
s 的锚元素上:
阻止跨域
为了避免本质上是用户介导的跨域信息泄漏,Blink 现在将忽略具有跨域属性的锚元素上存在的下载属性。请注意,这适用于
htmlAnchorElement.download
以及元素本身。Intent to Remove | Chromestatus Tracker | Chromium Bug
这打破了serverless downloads(对于跨域资源)。 它还破坏了 Reddit Enhancement Suite 的保存图像按钮 ( RES v5.12.0 fixed this 使用 chrome.downloads API(该扩展程序现在请求您允许管理下载)强>).res-media-controls-download
)
有什么解决方法吗?
更多细节在Web spec,谢谢@jbmilgrom
【问题讨论】:
“这会破坏无服务器下载” - 只有跨域下载,它不会“破坏”它们,它会故意禁用它们。 (好吧,我猜安全带也会“破坏”你穿过挡风玻璃的气流,如果你喜欢的话......这点故意仍然存在,因此要求“解决方法”恕我直言是相当无稽之谈。) 我的意思是任何不破坏网络的方法。如果我从另一个来源加载该资源并且我正在查看它,为什么要禁止我下载它? 我完全理解,这就是为什么我没有提交请求更改的错误,而是要求解决方法。在我看来,热链接应该通过其他足够的方式来解决。 我的意思是,即使目前有一种变通方法(不是说没有),那也只意味着他们对这项措施的实施仍然缺乏,他们很可能会修改它在这方面尽快......我怀疑从一开始就进入那个猫捉老鼠的游戏是否值得。我想如果你使用浏览器扩展而不是仅仅将用户脚本插入到网站上下文中,那么应该有可能从那里触发浏览器的实际的、本机的“安全...”功能。 “这与您的个人小用例无关......它是关于防止网站“热链接”文件以从第三方来源下载文件,“但浏览器仍然显示那些图像,将它们下载到工作内存中。那和保存图像到底有什么区别?右键单击->将链接另存为呢?打开开发者控制台并从开发者工具的源选项卡中保存图像怎么样?你那点居高临下的回答对任何人都没有帮助,何必回答呢? 【参考方案1】:根据discussionblob:
和data:
URL 不受影响,因此这里是使用fetch
和Blob 的解决方法。
客户端强制下载媒体
function forceDownload(blob, filename)
var a = document.createElement('a');
a.download = filename;
a.href = blob;
// For Firefox https://***.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 Web Store
(但设置 Access-Control-Allow-Origin: *
为我破坏了 YouTube)
性能
请注意,这种方法的性能不是很好!有时我的下载停滞时间
暴力猴/篡改猴
如果您的用例是用户脚本,则有 GM_download(options), GM_download(url, name)
⚠ 在 Tampermonkey 中这是一项测试功能,您必须先在 Tampermonkey Dashboard > Settings
中设置 下载模式: [Browser API ▾]【讨论】:
想知道文件大小超过 500MB 怎么办?我有哪些选择?我需要使用 StreamSaver.js 吗?我还有哪些其他选择?谢谢! 我知道问题是关于 chrome 的,但是在让它在 chrome 中很好地工作后,它在 Firefox 或 MS 浏览器中不起作用。 @nfdavenport 对不起,我忘了,在 Firefox 中,您必须将元素添加到 DOM 才能a.click()
***.com/a/32226068 似乎有效,也许就是这样。跨度>
@Leeroy 感谢您为 Firefox 和 Edge 工作。我不想为 IE11 填充我的应用程序以使获取工作,但如果我有 IE11 可能也可以工作。我收到“ReferenceError: 'fetch' is undefined”,但由于这是一个新项目,我将尝试支持 IE11。 :)
根据我的经验,在提示用户保存位置之前下载了整个文件。有没有办法让这个功能更像是常规下载,用户可以实时观看进度并提前选择保存位置?【参考方案2】:
显然,web specification 在某些时候更改为禁止跨域下载。在响应中添加content-disposition: attachment
标头,跨域下载可能会再次起作用。
【讨论】:
nginx 的例子:add_header Content-Disposition "attachment;";
这确实对我有用,但产生了一个新问题:src
url 具有上述响应标头的 iframe 现在行为异常:它们会导致自动下载 src 文件它们被渲染,另外它们的内容是空白的。
@LiranH 你有没有找到解决办法?
@Anthony 不怕
@LiranH 如果请求来自某个域而不是另一个域,我正在研究有条件地设置标头。使用 nginx 似乎很棘手,也许还有另一种方法。以上是关于Chrome 65 阻止跨域 <a 下载>。强制下载的客户端解决方法?的主要内容,如果未能解决你的问题,请参考以下文章
跨域读取阻止 (CORB) API-调用 Chrome 扩展
Youtube iframe api allow="autoplay" Chrome 65
Chrome 扩展 - 未捕获的 DOMException:阻止具有源的框架访问跨域框架