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

时间:2017-04-10 13:19:20

标签: javascript dom canvas cors base64

我需要将远程图像转换为base64给定其URL,但我遇到了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无法加载   https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg。没有   '访问控制允许来源'标题出现在请求的上   资源。起源' 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)} );

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

  

访问图像   ' https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg'   来自原产地' http://stackoverflow.com'已被CORS阻止   政策:否'访问控制 - 允许 - 来源'标题出现在   请求的资源。起源' http://stackoverflow.com'因此不是   允许访问。

还试过:

img.crossOrigin = 'anonymous';

得到了相同的结果。

方法3(使用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时失败:

  

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

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

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

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您可以通过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响应标头&需要任何其他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政策究竟在这里采取什么措施。

在这种特殊情况下,它根本不能防范任何事情,因为您可以使用任何服务器端编程语言或公共代理或curl或其他任何内容来https://blog.xenproject.org/wp-content/uploads/2014/10/Testing.jpg

https://blog.xenproject.org的维护者应正确配置自己的服务器,以发送Access-Control-Allow-Origin响应标头,告知浏览器允许从任何来源获取其内容。但由于他们没有,你只需要使用代理。

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