因为海报封面也就是上方的图片是文章封面图片,而文章封面图片是一个php随机图片api,导致不知道什么原因,点击预览海报可以看的到封面图片,下载下来就是一片空白Σ(゚д゚;)

一开始以为是php渲染延迟问题,但是搞了半天延迟多少秒都还是空白(/TДT)/

后边ai查出来是跨域问题,然后先是搞了nginx反代,但是最终代出来的图片地址还是源地址,或者说api那边有个策略不能跨域所以不行。最后试了php转发缓存到本地在发送过来,经历几个版本,图片可以正常显示了,但是海报这边下载出来还是空白,f12显示没有响应信息,最后把响应头加上,下载出来的海报才终于有封面了(〜 ̄△ ̄)〜

历经一天的不懈排查(用的ai)(ai太弱智要一步一步引导查找问题),终于在今天0:12分搞定了,可喜可贺

ヾ(≧∇≦*)ゝ

贴一下ai写的总结

✅ 根本原因分析

1️⃣ 直接原因:Canvas 被跨域图片污染

  • html2canvas在绘制时,如果图片来自 不同源(即使同域名但协议/端口不同也算跨域),且没有正确的 CORS 头,Canvas 会被标记为 tainted

  • 一旦 Canvas 被污染,调用 toDataURL()就会抛出安全错误,导致海报生成失败(空白或报错)。

2️⃣ 深层原因:PHP 代理没有返回 CORS 头

  • 虽然你使用了 file.221331.xyz的 PHP 代理来拉取 t.alcy.cc的图片,但 PHP 脚本没有返回 Access-Control-Allow-Origin响应头

  • 浏览器仍然认为图片是“跨域”的,因此 Canvas 仍然被污染。

3️⃣ 次要原因:图片未完全加载就开始截图

  • 大尺寸图片(2606×1591)加载较慢,如果在图片未完成加载时就调用 html2canvas,可能导致绘制空白。


✅ 最终解决方案(必须全部满足)

✅ 方案一:PHP 代理必须返回 CORS 头(最关键)

image.php最顶部​ 添加:

php

php

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Headers: Content-Type");
header("Cache-Control: public, max-age=86400");

✅ 方案二:前端图片必须声明 crossorigin="anonymous"

html

html

<img crossorigin="anonymous" src="https://file.221331.xyz/image.php?u=...">

✅ 方案三:等待图片完全加载后再截图

js

js

var img = document.querySelector('.dshare-poster-cover img');
if (img.complete) {
    startCapture();
} else {
    img.onload = startCapture;
    img.onerror = startCapture;
}

✅ 方案四:保留 html2canvas的必要配置

js

js

useCORS: true,
scale: 2,
backgroundColor: "#fff",
onclone: function(clonedDoc) {
    clonedDoc.getElementsByClassName("dshare-poster-crad")[0].style.transform = "none";
    clonedDoc.getElementsByClassName("dshare-poster-crad")[0].style.borderRadius = 0;
}

✅ 最终可用的一行代码(已验证)

js

js

$(".dshare-poster-download").off("click").on("click",function(e){e.stopPropagation();var t=$(".dshare-poster-crad"),img=t.find(".dshare-poster-cover img")[0];if(!img)return;function start(){var A=t.outerWidth(),e=t.outerHeight();r()(t[0],{height:e,width:A,useCORS:!0,scale:2,backgroundColor:"#fff",onclone(A){A.getElementsByClassName("dshare-poster-crad")[0].style.transform="none",A.getElementsByClassName("dshare-poster-crad")[0].style["border-radius"]=0}}).then(A=>{var e=document.createElement("a");e.href=A.toDataURL("image/png"),e.download="share-"+(+new Date)+".png",e.click(),$(".dshare-poster").click()})}img.complete?start():$(img).one("load",start).one("error",start)});

✅ 为什么之前会失败?

尝试

失败原因

直接引用 t.alcy.cc

跨域,Canvas 被污染

PHP 代理但未加 CORS 头

浏览器仍视为跨域

未等待图片加载

大图未完成,绘制空白

缺少 crossorigin="anonymous"

CORS 不完整

scale:1/ 无 onclone

样式错乱或模糊


✅ 现在状态

项目

状态

PHP 代理

✅ 正常

CORS 头

✅ 已添加

Canvas 污染

✅ 已解除

图片加载

✅ 等待完成

海报生成

✅ 100% 可用


🎯 一句话总结

PHP 代理解决了图片来源问题,但缺少 Access-Control-Allow-Origin头导致 Canvas 仍然被跨域污染;加上 CORS 头 + 等待图片加载 + 正确配置 html2canvas,问题彻底解决。