经纬志
首页 / 实战手册 / 瓦片

导出地图为图片时报 canvas tainted,前后排查了两小时

先看结论

截图按钮一点就抛 SecurityError,地图本身显示得好好的。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

点击「导出图片」后控制台报:

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 则图片能显示但画布被污染。 两种失败方式完全不同,容易误判。

排查过程

  1. 在网络面板选中一张瓦片,看响应头里有没有 access-control-allow-origin。
  2. 看该请求的 Request Headers → Origin,有没有带 Origin 说明是不是 CORS 请求。
  3. 把瓦片地址单独用一个带 crossOrigin 的 Image 加载,看是否报 CORS 错误。
  4. 确认截图范围是否包含非瓦片的第三方图片(气泡里的外链图标也常见)。
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'), '导出失败');

适用版本

组件版本说明
Leaflet1.9.xcrossOrigin 直接透传给 img
html2canvas1.4.1需 useCORS: true 且服务端支持
Chrome / Edge90 及以上tainted 检查严格,不提供降级
引用本文

经纬志(2026)。《导出地图为图片时报 canvas tainted,前后排查了两小时》。https://www.jingweizhi.com/cookbook/tile-cors-canvas.html(访问日期 2026-11-03)。