分享到 X/Twitter 不显示卡片图

分享 URL 到 X/Twitter 没图,即使 og:image 已设——Twitter 卡片有它自己的规则。

你把文章 URL 粘进 X(原 Twitter)的推文输入框,预期看到带大图的卡片,结果要么是干巴巴的链接,要么只有标题没图,要么显示的还是两周前已经换掉的旧图。同样的 URL 在 LinkedIn、Slack 都好好的。这几乎从来不是「X 又坏了」——通常是四件具体的事:缺 twitter:card 声明、og:image / twitter:image 抓取不到、图本身不符合 X 的尺寸/格式要求,或者 X 那边 7 天的卡片缓存还没过期。2026 年的现实是:X 已经把 Open Graph 当 fallback 在读,所以对大多数站点你不需要单独的 twitter:image——但你至少要有 twitter:card

5 秒判断你是哪种情况

  • 卡片有标题和描述但没图twitter:image / og:image 抓不到或图太小
  • 完全没有卡片,只是裸链接 → 整个 twitter:card meta 缺失,或者 content 值不被识别
  • 换了图后还是显示旧图 → X 卡片缓存
  • Facebook / LinkedIn 都正常,只有 X 不行twitter:image 用了相对路径,或 twitter:card 缺失
  • 新 URL 都正常,只有某一条不行 → 这条 URL 的图返回非 200(签名 URL 过期、文件已删)

常见原因(按命中率排序)

1. 缺 twitter:card 声明

没有 <meta name="twitter:card">,X 根本不知道要渲染成哪种形状的卡片,结果要么回退到小型 summary,要么完全不渲染。这是「首次分享没卡片」最常见的原因。

怎么判断:view-source 搜 twitter:card。没有就是它。

修复:至少输出

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="文章标题" />
<meta name="twitter:description" content="一句话摘要" />
<meta name="twitter:image" content="https://yourdomain.com/og/article.png" />

summary_large_image 是大多数内容站想要的 1.91:1 宽卡片;summary 是带小方图的紧凑卡。

2. twitter:image 用了相对路径

X 爬虫不会解析相对 URL。content="/og/foo.png" 直接被当字符串拿去 fetch,自然失败。

<!-- 错:相对路径 -->
<meta name="twitter:image" content="/og/article.png" />

<!-- 对:绝对 https URL -->
<meta name="twitter:image" content="https://yourdomain.com/og/article.png" />

怎么判断:view-source 看 content 属性,/./ 开头都是错的。

3. 图不符合 X 的尺寸/格式要求

X 对 summary_large_image 有硬性要求:

字段规则
格式PNG / JPEG / WebP(动图 GIF 可,但只取第一帧)
最小尺寸300 x 157 px
最大尺寸4096 x 4096 px
最大文件大小5 MB
宽高比1.91:1(偏离会被居中裁切)
协议只接受 HTTPS

200x200 的 favicon、6MB 的大图、http:// URL 都会静默失败——卡片可能还会渲染,但图位是空的。

怎么判断

curl -A "Twitterbot/1.0" -I "https://yourdomain.com/og/article.png"
# 期望 HTTP/2 200, content-type: image/png, content-length 小于 5000000
identify https://yourdomain.com/og/article.png   # ImageMagick 确认尺寸

content-length 超 5,000,000 或尺寸不到 300x157 就重新导出。

4. X 缓存了旧版本(7 天缓存)

X 按 URL 缓存卡片数据最长 7 天。你改完 meta 重发上线,但推文里还是旧图。2023 年起 cards-dev.twitter.com/validator 已被关闭,没有公开的「强制重抓」按钮。

怎么判断:URL 粘到 opengraph.devcardvalidator.io——它们会即时抓取,显示当前 meta 实际输出的卡片。若验证器显示新图但 X 还在显示旧图,就是 X 缓存。

修复(按有效性排序):

  1. URL 加个 cache-buster 参数:推 https://yourdomain.com/article/foo?v=2 而不是裸 URL。
  2. 等 7 天,缓存自然过期。
  3. 改 canonical URL(极少用,除非 slug 真换了)。

5. 图在 auth / CDN 签名 / 防盗链后

twitter:image 指向 Cloudinary 签名 URL、需要 Referer 的 CDN,或登录墙后的路径。Twitterbot 拿到的是 401 / 403 / 302。

curl -A "Twitterbot/1.0" -I "https://cdn.yourdomain.com/og/article.png"
# 200 + image/png 表示 OK
# 401 / 403 / 302 表示被挡

修复:把 OG 图放进静态 public/ 目录,或在 CDN 上白名单 Twitterbot/1.0 user-agent。

把 Open Graph 当 fallback(2026 年的实际行为)

2026 年 X 已经在缺 twitter: 命名空间时回退读 Open Graph。如果 og:image 设得对,你只要再加一行 <meta name="twitter:card" content="summary_large_image" /> 就够,可以省掉 twitter:image。2026 年内容站的推荐最小集:

<meta property="og:title" content="文章标题" />
<meta property="og:description" content="一句话摘要" />
<meta property="og:image" content="https://yourdomain.com/og/article.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://yourdomain.com/articles/article-slug/" />
<meta property="og:type" content="article" />

<meta name="twitter:card" content="summary_large_image" />

只有在你确实想让 X 用一张和 Facebook/LinkedIn 不一样的图时,才单独设 twitter:image

最短修复路径

按命中率排序:

  1. twitter:card(如果缺) → 修掉 ~45% 的「没卡片」情形
  2. twitter:image(或 og:image)改成绝对 https → 修掉 ~25%
  3. 图重新导出成 1200x630 PNG/JPEG,文件 < 1MB → 修掉 ~15%
  4. ?v=N 强刷,或等 7 天 → 修掉 ~10%
  5. CDN 白名单 Twitterbot / 把图移进 public/ → 最难的 5%

预防建议

  • 统一用 1200x630 PNG 或 JPEG,目标 < 500KB,从主域名(不要签名 CDN)出。
  • 用一个 helper 强制 og:image / twitter:image 一定是带协议的绝对 URL。
  • CI 加检查:每篇新文章的 OG 图 curl -A "Twitterbot/1.0" -I 确认 200、content-type 正确、content-length 小于 5MB。
  • 除非真要分平台用不同图,否则别设 twitter:image——让 X 回退读 og:image,少一个字段就少一处会漂移的地方。
  • OG 图按标题自动生成(@vercel/og、satori、puppeteer),从源头杜绝「忘加图」。

FAQ

Q:Twitter 老的卡片验证器死了,现在怎么测? A:用 opengraph.devcardvalidator.io,都会即时抓你的 URL 并模拟 X 的渲染。要看绝对真相,用一个小号发一次然后截图。

Q:改完 meta 还是显示旧图,X 多久会重抓? A:X 卡片缓存是 7 天,没有公开的强制刷新。最快的 workaround 是推的 URL 加 ?v=2——X 会当成新 URL 重抓。

Q:og:imagetwitter:image 都要写吗? A:不必。2026 年 X 把 og:image 当 fallback 在读。除非要分平台用不同图,否则只写一个就够。唯一必须的是 <meta name="twitter:card">

Q:卡片有图但裁切得很怪。 A:summary_large_image 强制 1.91:1。源图是 1:1 或 4:3 会被居中裁切。重新导出成精确的 1200x630。

Q:动图 GIF 只显示第一帧? A:是的,X 会拿第一帧定格。如果第一帧是黑底标题卡,卡片就像没图。直接用静态 PNG/JPEG。

Q:私信里 unfurl 正常,推文里不行。 A:私信预览是另一套即时抓取的管线,不走 7 天卡片缓存;推文渲染走卡片管线。两边表现不一致,就确认是缓存问题不是 meta 问题。

相关阅读

标签: #SEO #排查 #排查 #结构化数据 #Twitter Card #OG 图