导出地图为图片时报 canvas tainted,前后排查了两小时
截图按钮一点就抛 SecurityError,地图本身显示得好好的。
现象
点击「导出图片」后控制台报:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement':
Tainted canvases may not be exported.
或者在使用 html2canvas 时得到一张空白图,
底图区域全白,只有页面的文字和按钮正常。
原因
canvas 的安全模型规定:只要画布上绘制过来自其他源的图像,且该图像不是以
crossOrigin="anonymous" 方式加载并通过 CORS 校验,
画布就会被标记为 tainted,之后禁止读取像素。
关键在于两个条件必须同时满足:
- 图片元素带
crossorigin属性发起请求。 - 服务端响应包含
Access-Control-Allow-Origin,值与页面源匹配。
只设了 crossOrigin 而服务端没给头,图片会直接加载失败,
地图变成灰块;不设 crossOrigin 则图片能显示但画布被污染。
两种失败方式完全不同,容易误判。
排查过程
- 在网络面板选中一张瓦片,看响应头里有没有
access-control-allow-origin。 - 看该请求的
Request Headers → Origin,有没有带 Origin 说明是不是 CORS 请求。 - 把瓦片地址单独用一个带
crossOrigin的Image加载,看是否报 CORS 错误。 - 确认截图范围是否包含非瓦片的第三方图片(气泡里的外链图标也常见)。
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => console.log('可导出');
img.onerror = () => console.log('CORS 未通过,服务端缺少响应头');
img.src = 'https://tile.example.com/10/843/392.png';
解决方案
只给确实需要导出的瓦片开启 crossOrigin,同时要求服务端补上 CORS 头。
两者缺一不可。
// 前端:只在导出流程里启用
L.tileLayer('https://tile.example.com/{z}/{x}/{y}.png', {
crossOrigin: 'anonymous', // 发起 CORS 请求
maxZoom: 18
}).addTo(map);
// 服务端(Nginx)
add_header Access-Control-Allow-Origin "https://your-site.com" always;
add_header Access-Control-Allow-Methods "GET, HEAD" always;
服务端无法改动时,用同源代理把瓦片搬到自己域名下, 代理层带 CORS 头,前端就能正常导出。
// Nginx 反代瓦片
location /tiles/ {
proxy_pass https://tile.example.com/;
proxy_set_header Host tile.example.com;
add_header Access-Control-Allow-Origin "*" always;
}
// 前端改成本域地址,crossOrigin 可保留也可去掉
L.tileLayer('/tiles/{z}/{x}/{y}.png', { crossOrigin: 'anonymous' }).addTo(map);
验证
导出后 toDataURL 不再抛异常,图片中底图与叠加层都完整;
导出的 PNG 尺寸与地图容器一致。
const canvas = document.querySelector('.leaflet-layer canvas');
const url = canvas.toDataURL('image/png'); // 不抛 SecurityError
console.assert(url.startsWith('data:image/png'), '导出失败');
适用版本
| 组件 | 版本 | 说明 |
|---|---|---|
| Leaflet | 1.9.x | crossOrigin 直接透传给 img |
| html2canvas | 1.4.1 | 需 useCORS: true 且服务端支持 |
| Chrome / Edge | 90 及以上 | tainted 检查严格,不提供降级 |
经纬志(2026)。《导出地图为图片时报 canvas tainted,前后排查了两小时》。https://www.jingweizhi.com/cookbook/tile-cors-canvas.html(访问日期 2026-11-03)。