这个想法在概念上非常简单:我想创建一个用户脚本,让我按下一个按钮并在页面上保存一些东西(最常见和有问题的图像)。注意:用户脚本是注入客户端的脚本(通过浏览器扩展,如Tampermonkey和Greasemonkey),用于向站点添加功能。
为此,我只需要调用 saveAs()
函数并向其传递数据。
那么问题就变成了如何获取数据。
我见过的大多数方法都会遇到资源与脚本不在同一域的情况?(不确定这是如何工作的)。
现在,Tampermonkey(和Greasemonkey)创建了一个专门处理这个问题的函数 - GM_XMLHTTPRequest,它可以避免对正确CORS标头的需求。
但是,这会为已下载的文件创建对服务器的另一个请求。
我的问题是:有没有办法不必向服务器发送辅助请求?
以下是我努力的编年史:
根据我设法做的研究,你可以创建一个canvas
并在其中绘制图像。但是,这会"污染"画布,阻止它运行提取该数据的函数(例如.toBlob()
或.toDataURL()
)。
据我了解,CORS 提供了 2 种机制:设置正确的 HTTP 标头,这需要控制服务器,以及可以放在 HTML 元素上的特殊属性:crossorigin
我尝试在加载后添加此属性,但它不起作用,您仍然会得到受污染的画布。
Tampermonkey 提供了几个关于何时运行脚本的不同选项。所以下一个想法是在加载 DOM 时运行,但资源尚未被获取。似乎最早的可能是文档端(早些时候getElementById
调用返回null
)。但是,这当前在页面上加载图像时(在运行任何其他附加代码之前)返回错误: Image from origin '...' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '...' is therefore not allowed access.
Chrome中也有--disable-web-security
标志,但我宁愿不去那里。
不,如果没有对服务器的新请求,就无法做到这一点。
当发出第一个请求时,图像被浏览器标记为不安全,然后会阻止一些功能,如画布的toDataURL
、getImageData
或toBlob
,或者在音频文件的情况下,AudioContext的createMediaElementSource
和AnalyserNode
的方法,可能还有其他一些。
您无法规避此安全性,一旦它被标记为不安全,它就是不安全的。然后,您必须向服务器发出新请求,以这次以安全的方式从服务器获取新文件。
通常,您只需在执行请求之前以及在服务器正确配置为应答此类请求之后,在 media 元素上设置 crossOrigin
属性。
现在,在您的情况下,很明显您无法配置任何将使用脚本的服务器。
但正如你所注意到的,像GreaseMonkey或TamperMonkey这样的扩展可以访问比从网页运行的基本JavaScript更多的功能。在这些功能中,有一个允许您的浏览器对此类跨源请求不太小心,这就是GM_xmlhttpRequest
方法的作用。
但再一次,即使是扩展也没有足够的能力来取消标记不安全的媒体。
您必须使用安全性较低的方式执行新请求。