Back to Articles

Instant View 踩坑记:折腾了一整天,答案是「等一下」

一次花了大量时间修各种东西、最后发现核心问题是发通知太早了的经历

/Henri

事情从一个烦人的现象开始:同一个域名下的文章链接,发到 Telegram 里,有时候底部有 INSTANT VIEW 按钮,有时候没有;有时候点进去能正常阅读,有时候是白屏。

我以为搞个把小时就能解决。结果折腾了一整天。

第一层:IV 规则太脆弱

最先怀疑的是 Instant View 的匹配规则。打开一看,果然——之前的规则全靠 CSS 类名来定位内容,什么 text-xlmt-16 之类的。这些名字是 Tailwind 生成的样式标记,前端随便改一下排版,匹配就悄悄失效了,连个报错都没有。

于是我做了一件早就该做的事:在页面模板里加了一组 data-iv-* 属性。标题是 data-iv-title,正文是 data-iv-body,作者和发布时间也各有标记,导航栏之类不该被抓的元素标上 data-iv-ignore。然后 IV 规则只认这些语义标记,不再去猜页面长什么样。

改完之后,在 Telegram 的 IV 编辑器里一测,规则确实稳定了。我想这事应该差不多了吧。

第二层:同一个域名,两套页面

没差不多。

我忘了一件事:这个域名下不只跑着我的笔记站,还有主站的文档页面,HTML 结构完全不同。而 Telegram 的 IV 规则是按域名绑定的——一个域名只能有一套规则。

所以我的规则得同时覆盖两种完全不同的页面结构。最后用了一个"先后匹配"的方案:先试 data-iv-*,匹配不到就回退到主站那套 docs-content + md-theme-amp 的结构。不算优雅,但能用。

到这里我又觉得差不多了。

第三层:Bot 消息怎么写都不对

然后进入了最耗时的一个环节。

规则改好了,用 t.me/iv?url=...&rhash=... 裸链接手动粘贴到聊天里,IV 正常弹出。但 Bot 通过 API 发出来的消息,就是另一回事了。

我试了各种写法:把 IV 链接嵌在消息文本里、做成 inline 按钮、拆成两条消息、用 link_preview_options 指定预览 URL……每种写法在 Telegram 那边的反应都不一样,而且同一种写法隔一会儿再试,结果可能又变了。

这个阶段我最大的认知冲击是:手动粘贴一条链接和 Bot 通过 API 发一条消息,在 Telegram 内部走的可能根本不是同一条路。"手动能用"不等于"Bot 发也能用"。

花了好几轮实验,总算找到一套消息结构能比较稳定地挂出 IV 卡片。我松了口气。

插曲:.nojekyll 的低级失误

在这过程中还踩了一个完全不相关的坑。

之前把部署流程从 GitHub Actions 的官方 action 切换到手写 shell 脚本,结果忘了在发布目录里放 .nojekyll 文件。GitHub Pages 默认会用 Jekyll 处理静态文件,而 Jekyll 会忽略所有下划线开头的目录——比如 _next。Next.js 的所有 CSS 和 JS 资源都在 _next 里面。

所以页面变成了光秃秃的纯文本。HTML 加载了,但样式和交互全没了。浏览器里看着像是前端炸了,Telegram 去抓页面拿到的当然也是残缺的内容。

修复倒是一行代码的事:touch "${temp_dir}/.nojekyll"。但排查的时候根本没往这个方向想,因为症状看起来像是 CSS 写坏了。

以为快好了

修好 .nojekyll 之后,页面恢复正常了。IV 规则也稳定了。Bot 消息写法也调通了。我觉得这次真的差不多了。

部署一下,发条通知试试——

有时候有 IV 按钮,有时候没有。

我都快疯了。

真正的反转

反复试了几轮之后,我终于注意到一个规律:如果部署完马上发通知,IV 大概率挂不上;如果等几分钟再手动发链接,就没问题。

然后一切都说通了。

**GitHub Pages 的 CDN 传播需要时间。**代码推送到 gh-pages 分支之后,CDN 节点并不是立刻就能返回新内容。可能要几十秒,甚至一两分钟。而 Bot 的通知脚本是紧接着部署步骤运行的——这时候 Telegram 去抓取页面 URL,拿到的可能是旧版本,也可能是 404,也可能是正在更新中的不完整页面。

所以 Telegram 的 IV 引擎拿到了一个"坏"的页面,匹配失败或者渲染出白屏,然后还把这个结果缓存了。之后再怎么改规则、改消息写法,都没用——因为根本原因不在那些地方。

「等一下」就好了

最终的解决方案朴素得有点让人哭笑不得:等页面真正上线了再发通知。

我写了一个 wait-for-publication.js 脚本,部署完成后轮询刚发布的页面 URL。每 10 秒检查一次,最多等 3 分钟。检查的标准是:HTTP 返回 200,而且页面内容里包含 data-iv-body 或文章标题——这说明新版页面已经真正可以被外部访问了。

轮询通过之后,还额外 sleep 20 冷却一下,给 CDN 多留点缓冲时间。然后才运行 Telegram 通知脚本。

加上这个等待之后,IV 按钮就稳定了。

折腾了一整天改规则、改消息写法、修部署脚本,每一步都有收获,但都不是那个让 IV "时灵时不灵"的主因。最后的答案是:你发得太早了,页面还没准备好。

还有一点没法控制

还有一个残留现象:同一条 IV 链接反复打开,偶尔会白屏。第一次打开通常没问题,再点一次就可能只剩标题栏。

后来搞清楚了:这是 Telegram Web K 版(web.telegram.org/k)的客户端 bug。Web K 在关闭 IV 视图后没有正确清理内部状态,再次打开同一篇文章时,渲染管线的状态已经脏了,就白屏了。移动端完全不受影响——原生客户端的 IV 渲染引擎和 Web 版是两套完全不同的实现。至于 Web A 版(web.telegram.org/a),它压根不支持 IV,连按钮都不会出现。

所以 IV 在 Telegram Web 端就是二等公民。移动端能正常用就行,桌面端的读者走 Read More 链接直接看原文也不差。

延伸阅读

如果你也想给自己的静态站点配 Telegram Instant View,可以看看 《为静态站点配置 Telegram Instant View:从页面标记到部署等待》,那篇按正确顺序整理了完整的操作步骤,不用像我一样绕弯子。