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

CORS errors trying to convert remote image to base64 data

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

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

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

方法 1(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)} );

这会产生错误:

XMLHttpRequest cannot load https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://whosebug.com' is therefore not allowed access.

方法 2 (Canvas)

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)} );

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

Access to Image at 'https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg' from origin 'http://whosebug.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://whosebug.com' is therefore not allowed access.

也试过:

img.crossOrigin = 'anonymous';

得到了相同的结果。

方法 3(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';

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

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. at HTMLImageElement.img.onload (:9:22)

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

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

感谢您的帮助。

您可以通过 CORS proxy 发出请求来绕过 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)} );

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

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

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

您可以使用 https://github.com/Rob--W/cors-anywhere/ 等代码轻松设置您自己的 CORS 代理,而不是像此答案中的代码片段那样使用 third-party 代理。


As an aside, I'm not sure exactly what the CORS policy is protecting against here.

在这种特殊情况下,它根本没有真正保护任何东西,因为您可以使用任何 server-side 编程语言或 public 代理或 curl 或其他什么。

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

CORS 限制真正有用的唯一情况是内部网上的资源 运行 或某种防火墙后面的资源。因为在那种 intranet/firewall 情况下,让任意网络应用程序 运行 与 intranet/firewall.

中的用户具有相同的权限并不是一个好主意。