问题背景
在canvas中,单纯的渲染出跨域的图片并没有什么问题,但是要想用 getImageData() 或 toDataURL() 操作时,跨域图片就会报错,一般是类似下面这样的⬇️
或者是像html2canvas这样的插件,可以解析DOM生成base64的图片,中间也是借助canvas进行转换,如果DOM里遇到跨域图片同样会有问题
解决方法
最直接就是走 CORS(Cross-Origin Resource Sharing) 标准
- 第一步:
图片服务器必须配置响应头 Access-Control-Allow-Origin: *,或者具体的指定域名
- 第二步:
我们这边也要加处理,要使用支持跨域属性的元素<img>(还有<audeo>,<script>,<link>,<video>等都支持),给元素添加 crossOrigin = "anonymous" 属性;
在使用html2canvas插件时,DOM中用<img>标签、CSS背景图都可以,插件都会给你转成Image元素再渲染;
注意:但是你直接在 html 中图片上添加是 crossOrigin 无效的,插件会忽略掉,需要使用他提供的 useCORS: true 属性,然后就帮你加上跨域属性了。看它的源码⬇️
另外,allowTaint这个属性可以不用试了,在插件中貌似就是一个判断开关,目前看来没有影响
crossOrigin=anonymous相对于告诉对方服务器,你不需要带任何非匿名信息过来。例如cookie,因此,当前浏览器肯定是安全的。 就好比你要去别人家里拿一件衣服,相对于告诉对方,我只要衣服,其他都不要。如果不说,可能对方在衣服里放个窃听器什么的,就不安全了,浏览器就会阻止。 (摘自解决canvas图片getImageData,toDataURL跨域问题)
三、第三步:
如果在添加以上操作之前,你的手机设备已经访问过图片,缓存中也会存储响应头信息,所以可以还是无法显示图片;
可以在图片 src 上添加任意字符串,例如:
<img :src="popBless.icon + '?deleteCache'" >
网上常见的使用时间串的方式 new Date().getTime() 尽量不用,可能会有缓存击穿风险
其他方案
到目前为止,根据测试应该已经没有问题了,如果还出现跨域问题,可以看下是不是浏览器不支持 crossOrigin 属性;
可以尝试以下方案,思路都是多发一次请求,转成其他图片格式
blob格式图片 贴个原生代码意会一下:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var url = URL.createObjectURL(this.response);
// 在这里把url作为你的图片地址
...
// 图片用完后记得释放内存
URL.revokeObjectURL(url);
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
2、base64 格式
可以让后台同学帮忙提供图片链接转base64接口,也算比较常见的接口服务啦
完。
注: 本文html2canvas测试版本: 1.0.0-rc.5