先说结论
Odoo 的链接预览不是“每次看到 URL 都重新抓网页”。
它本质上是一套带缓存、关系映射、域名节流和数量上限的预览系统,目标是提升协作体验,而不是把消息系统变成无上限抓取器。
这就是为什么有些链接会秒出卡片,有些不会,有些又会沿用旧预览。
一、预览不是直接挂在消息正文里
源码里有两个层次:
mail.link.preview:存 URL 对应的预览数据mail.message.link.preview:存消息与预览的关系
这说明 Odoo 不想让每条消息都拷贝一份预览数据。
更合理的做法是:
- 相同 URL 复用同一个预览实体
- 每条消息只维护自己和预览的关联与顺序
这样既省存储,也方便更新和广播。
二、为什么不是所有链接都抓
_create_from_message_and_notify() 里有多道限制:
- 只从消息 HTML 里提取合格链接
- 会忽略某些站内 Odoo URL
- 单条消息最多只保留有限数量的预览
- 域名级节流命中后不再继续抓
这说明链接预览在 Odoo 里不是“尽可能多”,而是“够用且不失控”。
三、域名节流为什么很关键
_is_domain_thottled() 会按域名统计短时间内创建的预览数量,并结合配置参数判断是否节流。
这么做的意义很直接:
- 防止某个高频域名引发大量外部请求
- 降低消息系统被恶意链接刷爆的风险
- 避免贴很多相似链接时拖慢协作界面
也就是说,Odoo 很清楚链接预览虽然好看,但它本质上是在花网络和处理成本。
四、为什么旧预览会被复用
如果数据库里已经有相同 source_url 的预览,系统会优先复用,而不是重抓。
这是个很典型的协作产品思路:
- 预览信息通常不是秒级必须刷新
- 大多数情况下,复用已有卡片性价比更高
当然代价就是:
- 某些网页后来变了
- Odoo 里的预览可能不会立刻跟着变
但对消息协作来说,这通常是可以接受的折中。
五、为什么删除/更新也要通知前端
创建完或更新完消息预览后,源码会通过 Store / bus 把 message_link_preview_ids 推给前端。
这说明链接预览被视为消息对象的一部分协作视图,而不是后台懒得刷新的附属信息。
六、最容易踩的误区
误区 1:每个链接都应该立刻有预览
不对,可能被节流、过滤或超出数量上限。
误区 2:同链接每次都会重新抓
不对,命中缓存就复用。
误区 3:链接预览失败一定是 bug
不一定,很多时候是成本控制机制在生效。
七、排错顺序
当用户问“为什么这条消息没有预览卡片”时,建议按这个顺序查:
- 消息正文里是否真的是可解析链接
- 是否被站内 URL 过滤掉
- 同一消息是否已达到预览数量上限
- 该域名最近是否触发节流
- 是否已有旧预览被复用但前端尚未刷新
最后一句
Odoo 链接预览的核心设计,不是把网页抓得越全越好,而是在协作体验和系统成本之间找到一个可长期运行的平衡。
这也是它看起来“没那么激进”的原因。
DISCUSSION
评论区