问题背景

在使用 html2canvas 生成网页预览图时,如果页面中包含来自云存储(如 TOS、OSS 等)的外链图片,可能会遇到跨域问题。具体表现为,尽管在云存储服务中已经配置了跨域资源共享(CORS),但在生成预览图时仍然会报错,导致生成失败。

No 'Access-Control-Allow-Origin' header is present on the requested resource.

静态资源

静态资源(如图片)默认不会触发跨域资源共享(CORS)机制。即使你在云存储服务中配置了 CORS,浏览器在直接加载这些资源时也不会发送跨域请求(即不会触发 CORS 预检请求 OPTIONS)。因此,服务器不会返回 Access-Control-Allow-Origin 响应头,导致 html2canvas 在生成预览图时无法正确加载这些图片。

云储存外链响应头

云储存外链不返回Access-Control-Allow-Origin

 一般图片外链响应头

我们需要图片有Access-Control-Allow-Origin

 

问题验证

你可以通过以下步骤验证这个问题:

  1. 使用 HTTP 请求工具(如 Postman 或 curl)直接请求图片的 URL。
  2. 观察响应头,你会发现其中没有 Access-Control-Allow-Origin。
  3. 在请求头中手动添加 Origin 字段(可以填写任意网址),再次请求图片。
  4. 这次你会发现响应头中包含了 Access-Control-Allow-Origin,表明服务器已经正确处理了跨域请求。

问题解决

为了解决这个问题,你可以在生成预览图之前,先对图片 URL 进行一次带有 Origin 头的请求,以确保服务器返回正确的 Access-Control-Allow-Origin 响应头。具体步骤如下:

  1. 提取图片 URL:在生成预览图之前,遍历页面中的所有图片元素,提取出它们的 src 属性(即图片的 URL)。
  2. 发送带有 Origin 头的请求:对每个图片 URL,使用 fetch() 或 XMLHttpRequest 发送一个带有 Origin 头的请求。这个请求会触发服务器的 CORS 检查,并返回包含 Access-Control-Allow-Origin 的响应头。
  3. 生成预览图:在确保所有图片都正确加载后,再调用 html2canvas 生成预览图。
async function extractAndRequestImages() {
  const coverWrap = document.getElementById("page-design-canvas");
  if (!coverWrap) {
    console.warn("未找到 #cover-wrap");
    return;
  }

  const urls = new Set();
  const isHttpUrl = (url) => url.startsWith("http");

  // 获取 <img> 标签的 src
  coverWrap.querySelectorAll("img").forEach(img => {
    if (isHttpUrl(img.src)) {
      urls.add(img.src);
    }
  });

  // 获取背景图片 URL
  coverWrap.querySelectorAll("[style]").forEach(el => {
    const bgImage = el.style.backgroundImage;
    const match = bgImage.match(/url\(["']?(.*?)["']?\)/);
    if (match && isHttpUrl(match[1])) {
      urls.add(match[1]);
    }
  });

  // 将所有 URL 依次请求一次
  const headers = {
    Origin: window.location.origin, // 添加 Origin 头
  };

  for (const url of urls) {
    try {
      const response = await fetch(url, { method: "HEAD", headers });
    } catch (error) {
      console.warn(`请求失败: ${url}`, error);
    }
  }
}

总结

通过上述方法,你可以有效解决 html2canvas 在使用云存储外链图片时遇到的跨域问题。关键在于在生成预览图之前,确保所有图片都正确加载并返回了 Access-Control-Allow-Origin 响应头。这样,html2canvas 就能够顺利生成包含这些图片的预览图。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐