OG 图片工程:尺寸、体积、格式、重定向
有人把发布会链接丢进 WhatsApp:Slack 里卡片完整,WhatsApp 却完全没图。View Source 里 meta 看起来没问题,别的平台 debugger 也还能出图。于是你再导出一张更「清晰」的 1200×630 PNG,再发——WhatsApp 依然空白。
这不是品牌审美问题,而是 图片工程:真实爬虫视角下,og:image 的字节、MIME、跳转跳数与鉴权模型。
故障树:四种不同的「没图」
症状要分枝处理,混在一起会白耗几天。
| 现象 | 更可能的分支 | 先查什么 |
|---|---|---|
| 所有平台都没图 | 标签 / URL / 可达性 | 原始 HTML 是否有绝对 https://… 的 og:image;curl -sI 是否 200 |
| 换了文件仍是旧图 | 缓存 / cache key | URL 未变 → 平台沿用上次抓取(见重新抓取;系列缓存篇) |
| 图糊、裁切怪、构图崩 | 尺寸 / 宽高比 / 声明尺寸 | 真实像素 ≥ ~1200×630,约 1.91:1,安全区留白 |
| 只有某一端失败(常见 WhatsApp / IM) | 字节 / 格式 / 跳转 | 体积、JPEG vs 巨型 PNG、重定向深度、Content-Type 与文件魔数 |
空白卡片清单会覆盖相对路径、纯 JS 注入标签、爬虫被挡。本文只谈:标签已在时,图片资源本身为何挂。
尺寸与宽高比(必要,但不充分)
大型链接预览的行业默认仍是约 1200×630(约 1.91:1)。Facebook / Meta、LinkedIn、X 公布的推荐高度都在这一带(630 / 627 / 628)。工程上当作同一横幅槽位:按 1.91:1 设计,关键人脸与文案放在距边缘约 10% 的安全区内,并接受居中裁切。
<meta property="og:image" content="https://cdn.example.com/share/launch.jpg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="深色背景上的产品控制台截图" />
与扫描器打分一致的经验法则:
- 小于推荐尺寸 → 卡片发虚或被放大(
og-image-dimensions-too-small)。 - 远离 1.91:1 → 信息流裁切风险(
og-image-aspect-ratio-crop-risk)。 - 声明的宽高 ≠ 解码像素 → 部分客户端信 meta,版式错乱(
og-image-declared-size-mismatch)。 - 缺少
og:image:alt→ 无障碍与部分回退(og-image-alt-missing)。
如果你的导出只有 400×400 logo,再调 JPEG 质量也撑不起大横幅卡。
体积与格式(IM 静默丢图的主因)
像素讲设计故事;字节决定聊天客户端愿不愿意处理。
@vercel/og、Satori 以及很多「动态 OG」路径默认出 PNG。1200×630 的 PNG 动辄 数百 KB 到数 MB。当网站 hero 没问题,对某些 unfurl 路径却很不友好。
| 格式 | 何时合适 | 何时翻车 |
|---|---|---|
| JPEG | 照片、渐变、产品图;最稳妥的默认分享图 | 文字 + 扁平 UI 在质量过低时发糊 |
| WebP | 同等观感下通常更小(在支持的地方) | 客户端支持并不整齐;要最大化兼容时保留 JPEG 路径 |
| PNG | 锐利 UI、logo、硬边截图 | 体积爆炸;聊天预览往往最先丢 |
| GIF | 偶发动效 / 遗留 | 大、能力有限;不适合当默认发布图 |
字节预算因平台而异,且经常不是官方硬性文档。 在 OGKit 的平台档案里,WhatsApp 建模为约 300KB 硬上限 / 200KB 软目标,来源标注为 实测 / 社区共识——不是官方保证。其他档案允许数 MB 量级(Meta/Facebook 一类约 8MB,若干平台约 5MB),并列出偏好格式。所有硬数字都应视为运维向指引,不是合同。客户端行为变了就重新量。
若分享必须在聊天里稳:
- 导出 1200×630。
- 编 JPEG 质量约 80(或在你能控回退时用 WebP)。
- 在意 WhatsApp / IM 时,整体目标 约 100–300KB。
- 若边缘函数默认出 PNG,写进
og:image之前先转码。
扫描里对应规则:og-image-bytes-exceeds-platform-budget。
Content-Type 必须与字节一致
爬虫讨厌说谎的响应头。文件是 JPEG 魔数,却返回 Content-Type: image/png(或反过来),浏览器 <img> 可能仍能显示,部分客户端会直接拒收。
# 爬虫看到的头
curl -sI "https://cdn.example.com/share/launch.jpg" | rg -i 'HTTP/|content-type|content-length|location'
# 可选:对照魔数与扩展名
curl -sL "https://cdn.example.com/share/launch.jpg" | head -c 16 | xxd
稳定规则:og-image-content-type-mismatch。修源站或 CDN 映射,不要只改 meta。
重定向、签名 URL,以及「浏览器正常、分享 403」
浏览器会带 cookie、跟多跳 302、点营销短链。社交图片抓取是未登录、跳数有限的客户端。
常见翻车:
短链 → 鉴权墙 → CDN
og:image指向https://link.example/x,302 经过追踪再落到签名对象 URL。慢爬虫赶到时签名过期 → 403,空白卡。规则:og-image-forbidden。跳数过多
部分爬虫对图片 URL 几乎不跟跳转(即便 HTML 页会跟)。规则:og-image-redirects。Cookie / IP 白名单
团队 VPN 下正常的 staging CDN,对所有公网 unfurl 失败。
做法: 把最终、公开、HTTPS、匿名 200、长期或不可变的 CDN 对象 URL 直接写进 og:image。别让爬虫替你跑完重定向图。
# 看跳转链,别无限跟随
curl -sI -L --max-redirs 5 -A "facebookexternalhit/1.1" \
"https://example.com/og/launch.png"
最终 URL 与 meta 不一致就改 meta;任何一跳要鉴权,就别再用这条链做分享图。
同时保持绝对 HTTPS:og-image-relative-url、og-image-not-https。
可执行排查顺序(按序做,硬失败就停)
卡片「有时」没图时,按这个序列走:
原始 HTML 有标签吗?
curl -sL URL | rg -i 'og:image'
没有 → SSR / 注入问题(系列其他篇)。绝对 HTTPS?
相对路径或http://→ 先修 URL,再谈设计。用爬虫 UA 直接 GET 图片
curl -sI -A "facebookexternalhit/1.1" IMAGE_URL
期望 200、正确Content-Type、无鉴权。重定向预算
数Location跳数。图片 URL 最好 零跳。像素
解码真实宽高;对照 1200×630 与 1.91:1;若写了声明尺寸就对齐。字节
用Content-Length(或实际体积)对比你最在意的最严客户端。聊天权重高时,与其争论理论数 MB 上限,不如重新编码到几百 KB 以内。格式诚实
魔数、Content-Type、扩展名三者一致。仅某一平台仍是旧图
1–7 全绿仍旧 → 缓存,不是图片工程——走官方 rescrape。
扫描器已经写成规则的检查项
| 规则 id | 典型严重级别 | 抓住什么 |
|---|---|---|
og-image-missing |
error | 没有图片字段 |
og-image-relative-url |
error | 相对路径 |
og-image-not-https |
error | 非 HTTPS |
og-image-forbidden |
error | 401 / 403 / 鉴权 |
og-image-content-type-mismatch |
error | MIME ≠ 魔数 |
og-image-redirects |
warn | 图片 URL 会跳转 |
og-image-dimensions-too-small |
warn | 小于约 1200×630 |
og-image-aspect-ratio-crop-risk |
warn | 远离 1.91:1 |
og-image-declared-size-mismatch |
warn | meta 尺寸 ≠ 像素 |
og-image-bytes-exceeds-platform-budget |
warn | 超过平台字节预算 |
og-image-alt-missing |
warn | 缺少 alt |
分享图上线清单
- 专用导出 ≥ 1200×630,约 1.91:1,关键内容在安全区内
- JPEG(或经过验证的 WebP)压在最严相关字节预算内;聊天场景避免数 MB 的 PNG
-
og:image是最终、匿名 200 的 HTTPS CDN URL -
Content-Type与魔数一致;若写了og:image:width/height必须真实 -
og:image:alt是简短白话描述 - 换图后,对仍显示旧图的平台做 rescrape
用线上 URL 试一次
把生产页贴进首页扫描。图片相关发现会按规则 id 拆开——尺寸、预算、重定向、鉴权失败——而不是一张「看起来还行」的模拟卡。用报告驱动上面的排查顺序,在源站修一次,而不是无限重导 PNG。
系列下一篇: 缓存 TTL 与官方 rescrape(为什么图片 URL 正确仍显示上周活动图),以及动态 OG 路径里 PNG 默认值如何再次坑你。