前端 Canvas 绘制跨域图片 (如第三方图片、CDN 图片、不同域名图片)并导出时,浏览器会触发Canvas 污染(tainted canvas) 安全限制,导致:
toDataURL()/toBlob()直接报错- 无法导出图片、无法下载、无法上传
核心原因:Canvas 加载了未授权的跨域图片,浏览器禁止读取 / 导出画布内容。
一、根本原因(一句话)
图片域名 ≠ 你的网页域名,且图片服务器未开启跨域允许 + 前端未配置跨域加载 → Canvas 被标记为 "污染",禁止导出。
二、最简单、最通用的解决方案(前端 + 服务端 两步)
1. 前端代码:给图片添加跨域属性(必须)
javascript
// 1. 创建图片对象
const img = new Image();
// 2. ✅ 关键:开启跨域加载(必须放在 src 赋值之前)
img.crossOrigin = 'anonymous';
// 3. 设置图片地址
img.src = 'https://第三方域名/你的图片.jpg';
// 4. 图片加载完成后绘制 Canvas
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
// 绘制底图
ctx.drawImage(img, 0, 0);
// 绘制水印(文字/图片水印都可以)
ctx.font = '24px Arial';
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.fillText('我的水印', 50, 50);
// ✅ 现在可以正常导出,不会跨域报错
const base64 = canvas.toDataURL('image/png');
// 下载图片
const a = document.createElement('a');
a.href = base64;
a.download = 'watermark.png';
a.click();
};
2. 服务端配置:给图片资源开启跨域(必须)
必须让图片所在的服务器返回跨域头:
javascript
Access-Control-Allow-Origin: *
常见服务器配置示例
Nginx
javascript
location ~* \.(png|jpg|jpeg|gif|webp)$ {
add_header Access-Control-Allow-Origin *;
}
CDN(阿里云 / 腾讯云 / 七牛云)
直接在控制台开启 跨域配置 CORS ,添加 * 或你的域名即可。
本地开发
使用本地图片 / 同域名图片,不会出现跨域。
三、如果服务端不改配置?(叼他)
让后端把图片返回 Base64 字符串,前端直接绘制 Base64,完全没有跨域。
javascript
// 后端返回的 base64 字符串
const base64Img = 'data:image/png;base64,iVBORw0KGgo...';
const img = new Image();
img.src = base64Img; // 无跨域
img.onload = () => {
ctx.drawImage(img, 0, 0);
// 正常导出
};
总结
- 核心问题:跨域图片污染 Canvas,导致无法导出
- 标准方案:前端
crossOrigin="anonymous"+ 服务端开启CORS - 服务端不可改:用 Base64 或 后端代理
- 避坑:
crossOrigin必须放在src之前