ISR 解决「静态的快」与「动态的新」之间的矛盾:页面按 TTL 自动再生,但 TTL 之内的更新要等。要「发布即生效」,需要按需失效。
两种失效粒度
按路径(paths):精确、直接,适合单篇文章发布/编辑后失效自己的详情页。
await purge({ paths: ["/posts/my-post"] });
按标签(tags):批量、语义化。给一类页面打上同一个 tag,内容变更时一次失效整组:
// 路由登记
"/posts": { expiration: 300, tags: ["posts"] }
// 内容变更时
await purge({ tags: ["posts"] });
怎么选
| 场景 | 粒度 | 理由 |
|---|---|---|
| 单篇详情发布 | paths | 精确命中,不惊动别人 |
| 列表页(聚合多种来源) | tags | 被聚合的内容太多,逐条 paths 容易漏 |
| 全站样式改版 | 重新构建 | token 层改动影响所有页面,别用缓存失效糊弄 |
实践要点
- tag 设计对齐「失效动因」:tag 不是按 URL 形状分,而是按「什么数据变了会让它过期」分。
- 失效要挂在写入路径上:发布、编辑、删除的 API handler 里同步触发,不要靠人记得。
- TTL 是兜底不是主力:失效逻辑漏了,TTL 保证最终一致;但不能反过来把 TTL 设得很短来掩盖失效缺失。
一句话
缓存失效的难点从来不是 API,而是想清楚「哪条数据变了,哪些页面就旧了」——把这条映射写下来,purge 只是执行它。