Canvas 跨域图片数据获取
解决 Canvas 获取跨域图片时的污染问题
问题
在 Canvas 中使用跨域图片并尝试导出数据时,会报错:
Uncaught (in promise) DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported
这是因为 Canvas 认为跨域图片数据是”被污染的”,无法导出为 base64。
解答
为什么会被污染
当请求跨域图片时,如果未满足 CORS 条件,Canvas 会认为这些数据不可信。因为跨域图片可能包含敏感信息,直接使用可能暴露页面数据。
同域请求:Request Headers 带有 cookie,图片数据被 Canvas 信任。
跨域请求:默认情况下不符合 CORS 条件,图片数据不被 Canvas 信任。
解决方案
使用 <img> 元素的 crossOrigin 属性,该属性有两个值:
anonymous:CORS 请求时不发送认证信息use-credentials:CORS 请求时发送认证信息(如 cookie)
代码示例
// 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 = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, img.width, img.height);
};
img.src = 'https://b.com/a.png';
必须满足的三个条件
-
img 元素设置 crossOrigin 属性:启用 CORS 请求
-
服务器允许跨域:响应头设置
Access-Control-Allow-Origin -
避免使用缓存:URL 加时间戳或设置
Cache-Control: no-cache
为什么要避免缓存
如果图片已通过 <img> 标签加载并缓存,后续用 JavaScript 请求时会直接返回缓存。如果缓存中的图片不是通过 CORS 请求的,或响应头中没有 Access-Control-Allow-Origin,就会导致报错。
关键点
- Canvas 使用跨域图片必须通过 CORS 请求,否则会被标记为”污染”
- 在 img 元素上设置
crossOrigin = 'anonymous'启用 CORS - 服务器必须返回
Access-Control-Allow-Origin响应头 - 避免使用非 CORS 方式缓存的图片,可通过添加时间戳解决
目录