跳到主要内容

如何解决 CORS 跨域问题

Ydesign 在加载图片到 Fabric 画布时,默认会给每张图片加上 crossOrigin="anonymous" 属性(这是"导出画布时不被污染 / 不报错"的前提)。

但如果图片所在的服务器没有返回对应的 CORS 响应头,你就会看到这个经典错误:

Access to image at 'http://example.com/image.jpg' from origin 'http://your-domain.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

一旦出现这个错误,图片加载不上来,就算加载上来画布也会被"污染"(tainted),导致后续 store.toDataURL() / store.toBlob() / saveAsImage() 全部抛错。

本文说明如何彻底解决它。


① 让图片服务器返回 CORS 响应头(根治方案)

这是最正确、最该做的事情。只需要在服务器的响应里加上:

Access-Control-Allow-Origin: *

常见对象存储平台的配置方式

AWS S3:在 Bucket → Permissions → CORS configuration 里加:

[
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3000
}
]

详见 AWS 官方文档

阿里云 OSS / 腾讯云 COS:控制台 → 跨域访问 CORS → 添加规则:

  • 来源 Origin:*(或你的域名列表)
  • 允许方法:GETHEAD
  • 允许 Headers:*

Cloudflare R2:在 R2 Bucket 的 Settings 里加 CORS 规则,字段同上。

自建 Nginx / 后端服务器:给图片响应加头即可:

location ~* \.(png|jpg|jpeg|webp|svg|gif)$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, HEAD';
}

CDN 层面

如果你的图片走 CDN,有些 CDN 会自动剥掉源站的 CORS 头,需要在 CDN 面板里显式开启"CORS 响应头透传"或直接配置 CORS 规则。Ydesign 官方默认使用的一份默认 CDN 已开启。


② 确保所有 <img> 标签都带 crossOrigin 属性

浏览器对每张图片只会建立一个缓存。如果你的页面在别处(比如素材面板的预览图、上一步的确认页)先用不带 crossOrigin 的方式加载了它,再进画布时浏览器就会复用那份"污染"的缓存,导致 crossOrigin='anonymous' 无效。

解决方法:页面上所有展示用户图片的地方都加 crossOrigin="anonymous"

// ❌ 错误示范
<img src="http://example.com/image.jpg" />

// ✅ 正确示范
<img src="http://example.com/image.jpg" crossOrigin="anonymous" />

如果你使用 Ydesign 内置的 <ImagesGrid /> 渲染素材面板,它已经默认带了 crossOrigin="anonymous",无需额外处理。


③ 如何排查是哪张图片出了问题?

store.toDataURL() 抛出 tainted canvas 错误时,可以遍历所有图片检查:

import { observer } from 'mobx-react-lite';

const urls = store.objects.filter(o => o.type === 'Image').map(o => o.src);

for (const url of urls) {
try {
const res = await fetch(url, { mode: 'cors' });
const hasCors = !!res.headers.get('access-control-allow-origin');
console.log(hasCors ? '✅' : '❌', url);
} catch (e) {
console.log('❌', url, e.message);
}
}

命令行里找到问题图片之后,按 ① 的方式修复对应服务器的 CORS 配置即可。


④ 降级方案:后端代理(不得已时)

如果图片源站实在无法配置 CORS(比如是第三方 API、上游合作方),可以在自己的后端做一层代理

// Express 示例
app.get('/proxy/image', async (req, res) => {
const target = req.query.url;
const upstream = await fetch(target);
const buffer = Buffer.from(await upstream.arrayBuffer());
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Content-Type', upstream.headers.get('content-type') || 'image/jpeg');
res.send(buffer);
});

然后在画布里使用代理 URL:

store.addElement({
type: 'Image',
src: `/proxy/image?url=${encodeURIComponent('https://third-party.com/image.jpg')}`,
});

⚠️ 代理方案会增加后端负载 + 流量成本,只在万不得已时使用。


延伸阅读