尝试将远程图像转换为 base64 数据的 CORS 错误

Chr*_*ris 8 javascript base64 dom canvas cors

我需要根据其 URL 将远程图像转换为 base64,但我遇到了 CORS 错误并且不确定如何解决。

我遵循了关于这个问题的一些解决方案:How to convert image into base64 string using javascript

我的示例图片是:https : //blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg

方法一(FileReader):

function toDataUrl(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var reader = new FileReader();
    reader.onloadend = function() {
      callback(reader.result);
    }
    reader.readAsDataURL(xhr.response);
  };
  xhr.open('GET', url);
  xhr.responseType = 'blob';
  xhr.send();
}

toDataUrl('https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg', function(data) { console.log(data)} );
Run Code Online (Sandbox Code Playgroud)

这会产生错误:

XMLHttpRequest 无法加载 https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问源“ http://stackoverflow.com ”。

方法 2(画布)

function toDataUrl(src, callback, outputFormat) {
  var img = new Image();
  img.crossOrigin = 'use-credentials';
  img.onload = function() {
    var canvas = document.createElement('CANVAS');
    var ctx = canvas.getContext('2d');
    var dataURL;
    canvas.height = this.height;
    canvas.width = this.width;
    ctx.drawImage(this, 0, 0);
    dataURL = canvas.toDataURL(outputFormat);
    callback(dataURL);
  };
  img.src = src;
  if (img.complete || img.complete === undefined) {
    img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
    img.src = src;
  }
}
toDataUrl('https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg', function(data) { console.log(data)} );
Run Code Online (Sandbox Code Playgroud)

尝试加载图像时产生类似的错误:

从源 ' http://stackoverflow.com '访问“ https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg ”上的图像已被 CORS 策略阻止:无“访问” -Control-Allow-Origin' 标头存在于请求的资源上。因此,不允许访问源“ http://stackoverflow.com ”。

还尝试过:

img.crossOrigin = 'anonymous';
Run Code Online (Sandbox Code Playgroud)

并得到了相同的结果。

方法三(Canvas 使用 img 元素):

img = document.createElement('img');
img.onload = function() {
    var canvas = document.createElement('CANVAS');
    var ctx = canvas.getContext('2d');
    var dataURL;
    canvas.height = this.height;
    canvas.width = this.width;
    ctx.drawImage(this, 0, 0);
    dataURL = canvas.toDataURL('image/jpg');
    console.log(dataURL);
};
img.src = 'https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg';
Run Code Online (Sandbox Code Playgroud)

这种方式至少加载图像,但在调用 toDataURL 时失败:

未捕获的 DOMException:无法在“HTMLCanvasElement”上执行“toDataURL”:可能无法导出受污染的画布。在 HTMLImageElement.img.onload (:9:22)

顺便说一句,我不确定 CORS 政策到底在保护什么。假设存在某种可能触发漏洞利用的恶意负载。我们仍然在 DOM 中加载和显示图像,为什么我们会信任由同一端点设置的 CORS 标头?

有谁知道这个问题的任何解决方案?

谢谢你的帮助。

sid*_*ker 10

您可以通过CORS 代理提出请求来绕过 CORS 限制,如下所示:

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
   targetUrl = 'https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg'
toDataUrl(proxyUrl + targetUrl,
  function(data) { console.log(data)} );
Run Code Online (Sandbox Code Playgroud)

代理将请求发送到targetUrl,然后在获得响应后,添加Access-Control-Allow-Origin响应头和所需的任何其他 CORS 响应头,最后将其传递回您的请求代码。

Access-Control-Allow-Origin添加了标头的响应是浏览器看到的,因此浏览器让您的前端代码访问响应,并且您不会收到任何 CORS 错误。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS解释了正在发生的事情导致需要配置请求的服务器,以便它发送必要的 CORS 标头,或者否则在中间放置一个代理来为您添加 CORS 标头(如上所述)。

而不是像本答案中的代码片段那样使用第三方代理,您可以使用https://github.com/Rob--W/cors-anywhere/或类似的代码轻松设置自己的 CORS 代理.


顺便说一句,我不确定 CORS 政策到底在保护什么。

在这种特殊情况下它不是真正的保护反对所有的东西,因为你可以得到https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg使用任何服务器端编程语言或公共代理curl或其他。

https://blog.xenproject.org的维护者应该正确地将他们的服务器配置为发送一个Access-Control-Allow-Origin响应头,告诉浏览器允许从任何来源获取他们的内容。但既然他们没有,你只需要使用代理。

CORS 限制真正有用的唯一情况是在 Intranet 上运行或以其他方式在某种防火墙后面运行的资源。因为在 Intranet/防火墙的情况下,让任意 Web 应用程序以与 Intranet/防火墙内的用户相同的权限运行并不是一个好主意。