这篇文章发布于 2018年02月10日,星期六,23:27,归类于 Canvas相关。 阅读 113331 次, 今日 1 次 19 条评论
by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=7378
本文可全文转载,但需要保留原作者和出处。
一、首先,图片服务器需要配置Access-Control-Allow-Origin
一般团队都会有一个专门域名放置静态资源,例如腾讯是gtimg.com
,百度是bdimg.com
;或者很多团队使用的是腾讯云或者阿里云的服务。
而主页面所在域名往往不一样,当需要需要对canvas图片进行getImageData()
或toDataURL()
操作的时候,跨域问题就出来了,而且跨域问题还不止一层。
首先,第一步,图片服务器需要配置Access-Control-Allow-Origin信息,例如:
如PHP添加响应头信息,*
通配符表示允许任意域名:
header("Access-Control-Allow-Origin: *");
或者指定域名:
header("Access-Control-Allow-Origin: www.zhangxinxu.com");
此时,Chrome浏览器就不会有Access-Control-Allow-Origin相关的错误信息了,但是,还会有其他的跨域错误信息。
二、canvas图片getImageData cross-origin跨域问题
对于跨域的图片,只要能够在网页中正常显示出来,就可以使用canvas的drawImage()
API绘制出来。但是如果你想更进一步,通过getImageData()
方法获取图片的完整的像素信息,则多半会出错。
举例来说,使用下面代码获取github上的自己头像图片信息:
var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var img = new Image(); img.onload = function () { context.drawImage(this, 0, 0); context.getImageData(0, 0, this.width, this.height); }; img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
结果在Chrome浏览器下显示如下错误:
Uncaught DOMException: Failed to execute ‘getImageData’ on ‘CanvasRenderingContext2D’: The canvas has been tainted by cross-origin data.
Firefox浏览器错误为:
SecurityError: The operation is insecure.
如果使用的是canvas.toDataURL()方法,则会报:
Failed to execute ‘toDataURL’ on ’HTMLCanvasElement’: Tainted canvased may not be exported
原因其实都是一样的,跨域导致。
那有没有什么办法可以解决这个问题呢?
可以试试crossOrigin
属性。
三、HTML crossOrigin属性解决资源跨域问题
在HTML5中,有些元素提供了支持CORS(Cross-Origin Resource Sharing)(跨域资源共享)的属性,这些元素包括<img>
,<video>
,<script>
等,而提供的属性名就是crossOrigin
属性。
因此,上面的跨域问题可以这么处理:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = '';
img.onload = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, this.width, this.height);
};
img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
增加一个img.crossOrigin = ''
即可,虽然JS代码这里设置的是空字符串,实际上起作用的属性值是anonymous
。
crossOrigin
可以有下面两个值:
关键字 | 释义 |
---|---|
anonymous | 元素的跨域资源请求不需要凭证标志设置。 |
use-credentials | 元素的跨域资源请求需要凭证标志设置,意味着该请求需要提供凭证。 |
其中,只要crossOrigin
的属性值不是use-credentials
,全部都会解析为anonymous
,包括空字符串,包括类似'abc'
这样的字符。
例如:
img.crossOrigin = 'abc';
console.log(img.crossOrigin); // 结果是'anonymous'
另外还有一点需要注意,那就是虽然没有crossOrigin
属性,和设置crossOrigin="use-credentials"
在默认情况下都会报跨域出错,但是性质上却不一样,两者有较大区别。
crossOrigin兼容性
IE11+(IE Edge),Safari,Chrome,Firefox浏览器均支持,IE9和IE10会报SecurityError安全错误,如下截图:
四、crossOrigin属性为什么可以解决资源跨域问题?
crossOrigin=anonymous
相对于告诉对方服务器,你不需要带任何非匿名信息过来。例如cookie,因此,当前浏览器肯定是安全的。
就好比你要去别人家里拿一件衣服,crossOrigin=anonymous
相对于告诉对方,我只要衣服,其他都不要。如果不说,可能对方在衣服里放个窃听器什么的,就不安全了,浏览器就会阻止。
五、IE10浏览器不支持crossOrigin怎么办?
我们请求图片的时候,不是直接通过new Image()
,而是借助ajax和URL.createObjectURL()
方法曲线救国。
代码如下:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var url = URL.createObjectURL(this.response);
var img = new Image();
img.onload = function () {
// 此时你就可以使用canvas对img为所欲为了
// ... code ...
// 图片用完后记得释放内存
URL.revokeObjectURL(url);
};
img.src = url;
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
此方法不仅IE10浏览器OK,原本支持crossOrigin的诸位浏览器也是支持的。
也就多走一个ajax请求,还可以!
根据,根据实践发现,在IE浏览器下,如果请求的图片过大,几千像素那种,图片会加载失败,我猜是超过了blob尺寸限制。
六、结束语
最近工作中学到的一点小经验,希望可以帮到遇到类似问题的小伙伴。
感谢阅读!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=7378
(本篇完)
- CORS ajax跨域请求php简单完整案例一则 (0.739)
- 使用wavesurfer.js显示mp3 audio音频的波形图 (0.441)
- Web referrer策略详解与防盗链图片的显示 (0.410)
- 图片加载失败后CSS样式处理最佳实践 (0.377)
- 使用jsPDF导出PDF文件实践分享 (0.359)
- 快速了解window.name特性与作用 (0.328)
- 使用CSS将图片转换成模糊(毛玻璃)效果 (0.261)
- JS实现图片相似度的判断 (0.261)
- CSS3 box-shadow盒阴影图形生成技术 (0.213)
- 图片主色获取脚本rgbaster.js小介绍小使用 (0.213)
- 照片位图转SVG矢量图片JS工具primitive.js等简介 (RANDOM - 0.030)
本地canvas从video获取像素不行。
实在不行,nginx里面开一个代理,或者后端做一个代理接口,把跨域都干掉
在chrome测试,不管anonymous还是ajax,都会携带Origin去请求,只要对面图片的Access-Control-Allow-Origin设置的不是本页面,就会跨域。也就是说该不允许的还是不允许
在IOS12上好像不行
无论怎么设置,只要toDataURL, 都会报错
文章中关于 crossOrigin 属性:anonymous 和 use-credentials 没有解释清楚。
anonymous
从翻译角度来看是 匿名 的意思,表示不携带任何用户信息去获取资源,只会通过http头数据校验数据是否可用。
技术要点:请求中不会携带用户信息,例如cookie。请求头中会有origin数据,需要与响应头的 access-control-allow-origin 字段值相匹配。
use-credentials
字面意思为使用凭证,表示请求会携带用户信息,服务端会校验请求凭证信息并且发送给浏览器,浏览器根据响应信息,判断是否采用响应数据。
技术要点:请求中携带用户信息(例如,cookie)。请求头中会有origin数据。响应头中会有 access-control-allow-origin 数据,该数据必须是具体的域名,不能为通配符*,需要与请求头的origin相匹配。响应头中的 access-control-allow-credentials 需要为 true ,表示允许请求中携带凭证信息(例如,cookie);其他情况下,不符合要求,浏览器将不会把响应内容返回给请求的发送者。
对,跨域问题本质上是为了避免csrf风险,只要不允许带cookie等用户信息就可以跨域,anonymous所谓的匿名其实是指不携带用户侧的信息,而不是服务器侧的信息,所以文章里说的有失偏颇。
安卓11 :1,2步都设置了,但是还是无法调用canvas.ToDataURL。有人碰到相同情况吗?ios和一部安卓10的手机没有问题
尝试了一下,http的图片可以,但是对https图片还是报错,我用的百度的logo
https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
亲测,IE11也存在跨域问题
一开始把crossOrigin设置在img标签内 发现不行
后来试了 new Image() 的写法可以了
貌似必须使用img.crossOrigin = ‘anonymous’这种写法
将图片服务器上的图片进行标记之后转换为base64编码,但是出现Uncaught DOMException: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.错误!
Safari还是不行啊 出现这个错误 The operation is insecure. 如果不行的话 那不是ios手机上就不能使用了。
可以了 用blob的方式可以解决Safari的问题
能给出具体解决方法吗不太熟悉
非常赞,很是感谢
很不错
每天关注鑫大神的空间,自己的经验每天都会涨一点~
虽然有crossOrigin这个属性 , 但是要达到正常的getImageData还是需要服务器那边支持跨域才行吧~ , 就像上一篇文章里说的那样
前辈你好,最近在做audio的canvas频谱图,
//连接方式:source → analyser → destination
遇到的问题就是使用本地static音频文件的时候正常,用网上的连接就会报跨域问题,我找了一些资料,他们给的解决也是crossorigin,但是设置之后就被403了(谷歌也是版本皆为最新)
火狐报错:
已拦截跨源请求:同源策略禁止读取位于 http://m10.music.126.net/20180211152619/984afca11628ed48d15703a6b9f83383/ymusic/1370/452a/f846/a98bb4e0b0374d5b25c0694c534d5056.mp3 的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin’)。
没有设置crossorigin的情况
传递到 createMediaElementSource 的 HTMLMediaElement 有一个跨源资源,该节点将输出无声。