怎么解决canvas中获取跨域图片数据的问题?

背景

在一张图片添加相关文字,然后转化为base64数据,上传至服务器

当代码上线写完部署到测试环境,控制台报出如下错题:

Uncaught (in promise) DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported

这是因为页面在请求图片时产生跨域情况,canvas认为该图片数据为污染的数据,是不安全的数据,无法导出base64数据

为什么 canvas 认为跨域图片数据为 污染的数据

当请求跨域图片数据,而未满足跨域请求资源的条件时

如果canvas使用未经跨域允许的图片的原始数据,这些是不可信的数据,可能会暴露页面的数据

请求图片资源 - 同域

Request Headers带有cookie。图片数据是被canvas信任的

请求图片资源 - 跨域

默认情况下,直接请求跨域图片。因为不符合跨域请求资源的条件,图片数据是不被canvas信任的。

为了解决图片跨域资源共享的问题, <img> 元素提供了支持的属性:crossOrigin,该属性一共有两个值可选:anonymous 和 use-credentials,下面列举了两者的使用场景,以及满足的条件。

anonymoususe-credentials
用途匿名请求跨域图片资源,不会发送证书(比如cookie等)具名请求跨域图片资源,会携带证书数据
Request Headersoriginorigin、cookie
Response headersAccess-Control-Allow-OriginAccess-Control-Allow-Origin、Access-Control-Allow-Credentials
所需条件Access-Control-Allow-Origin 字段值需要包含请求域。Access-Control-Allow-Origin 字段值需要包含请求域,且不能为通配符 *。Access-Control-Allow-Credentials 字段值需要为 true,表明允许请求发送证书数据。

代码示例

// page origin is https://a.com

const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');

const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
   context.drawImage(this, 0, 0);
   context.getImageData(0, 0, img.width, img.height);
};
img.src = 'https://b.com/a.png';

另外,跨域图片能正常裁剪(图片未转化成base64),应该满足三个条件:

  • img元素中设置crossorigin属性
  • 图片允许跨域,设置响应头Access-Control-Allow-Origin
  • 使用js方式请求图片资源, 需要避免使用缓存,设置url后加上时间戳,或者http头设置Cache-Control为no-cache

主要原因是:

  • 如果使用跨域的资源画到canvas中,并且资源没有使用CORS去请求,canvas会被认为是被污染了, canvas可以正常展示,但是没办法使用toDataURL()或者toBlob()导出数据,见Allowing cross-origin use of images and canvas。 所以通过在img标签上设置crossorigin,启用CORS,属性值为anonymous,在CORS请求时不会发送认证信息,见HTML attribute: crossorigin。
  • 在启用CORS请求跨域资源时,资源必须允许跨域,才能正常返回,最简单的方式设置响应头Access-Control-Allow-Origin
  • 图片已经通过img标签加载过,浏览器默认会缓存下来,下次使用js方式再去请求,直接返回缓存的图片,如果缓存中的图片不是通过CORS 请求或者响应头中不存在Access-Control-Allow-Origin,都会导致报错

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海屿鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值