根本原因是浏览器同源策略主动限制:跨域图片未经cors授权加载后,canvas被标记为“污染”,导致todataurl()等方法报错;必须前端设img.crossorigin='anonymous'且服务端返回access-control-allow-origin响应头,二者缺一不可。

Canvas 绘制跨域图片时被阻止,根本原因不是代码写错了,而是浏览器主动执行了安全限制——一旦跨域图片未经许可加载进 Canvas,画布就会被标记为“污染”,后续调用 toDataURL() 或 toBlob() 就会直接报错。
为什么跨域图片会让 Canvas “变脏”
浏览器的同源策略不允许脚本读取不同源资源的像素数据。即使图片在页面上显示正常,只要它来自其他域名,且没有走合规的跨域流程,Canvas 就无法从中提取数据。这不是 bug,是设计好的防护机制,防止恶意网站窃取用户头像、截图等敏感信息。
典型表现包括:
- 截图空白,或部分图片缺失
- 控制台报错:
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported - Network 面板里图片响应头缺少
Access-Control-Allow-Origin
必须同时满足的两个条件
要让跨域图片“干净地”进入 Canvas,前端和后端缺一不可:
-
前端:给
<img>标签设置crossorigin="anonymous",或在创建Image对象时手动赋值img.crossOrigin = "anonymous" -
后端:图片资源响应头中必须包含
Access-Control-Allow-Origin(例如Access-Control-Allow-Origin: *或指定域名)
只做前端设置而服务端没配 CORS 头,请求仍会被拦截;只配了服务端但前端没设 crossOrigin,浏览器不会发送带 Origin 的请求,服务端也就不会返回 CORS 头——两者必须配合。
html2canvas 中的 useCORS 参数怎么用
使用 html2canvas 截图时,不能只靠 useCORS: true 就万事大吉。它只是告诉库“尝试用 CORS 方式加载图片”,前提是:
- 所有图片标签已带有
crossorigin="anonymous" - 对应图片服务器返回了合法的 CORS 响应头
- 同时设置
allowTaint: false(否则即使加载成功,Canvas 仍可能被污染)
示例配置:
html2canvas(element, {
useCORS: true,
allowTaint: false,
logging: true
})
开启 logging: true 可以在控制台看到资源加载详情,方便排查哪张图卡住了。
如果无法控制图片服务器怎么办
比如你引用的是第三方图床、CDN 或用户上传的外链图,自己没法改对方服务器配置,这时就该换思路:
- 用代理接口中转图片请求(前端请求自己的后端,后端再 fetch 图片并透传响应头)
- 服务端预处理图片:下载、重存到自己域名下,再渲染
- 对用户上传图,强制前端先用
FileReader读取本地文件,避免跨域
代理方案最常用,但要注意设置合理的缓存与限流,避免成为公开爬虫入口。











