博客CDN缓存自动化:从发现到修复

2026年06月25日1 次阅读0 人喜欢
Next.jsCDN腾讯云CI/CD缓存
所属合集

博客 CDN 缓存自动化:从发现到修复

起因:Chat 页面缓存问题

事情是这样的,我给博客加了个 AI 聊天功能,页面放在 /chat 路径下。按理说这是个 "use client" 的客户端渲染页面,CDN 不应该缓存才对。

结果发现——CDN 不仅缓存了,还缓存了一年。

排查过程

先看响应头:

复制代码
x-nextjs-cache: HIT
x-nextjs-prerender: 1
Cache-Control: s-maxage=31536000

31536000 秒,差不多就是一年。关键是这个 header 是 Next.js 自己返回的,不是 CDN 加的。

原因很简单:虽然 /chat"use client" 组件,但 Next.js 仍然对它做了预渲染(生成初始 HTML shell)。页面没有声明 export const dynamic = 'force-dynamic',所以被当成静态页处理了。prerender-manifest.json 里白纸黑字写着:

json 复制代码
"/chat": {
    "initialRevalidateSeconds": false,
    "srcRoute": "/chat"
}

false 意味着永不 revalidate,Next.js 就给了个一年的 s-maxage

修复:revalidate + CDN 自动刷新

最简单的修复是加一行:

ts 复制代码
export const revalidate = 3600; // 1小时

这样 Next.js 还是预渲染(保留 SEO 优势),但 s-maxage 从一年变成了 3600 秒。

但这只是治标。部署新版本后,CDN 还是会继续缓存旧内容直到 TTL 过期。我需要的是:部署完成后自动刷新 CDN 缓存

搭建 CDN 自动刷新

方案选型

一开始想在 GitHub Actions 里做,但发现服务器上的腾讯云 SecretId/SecretKey 只在 Docker 容器的环境变量里,GitHub Actions 拿不到。也不想为了这事单独在 GitHub Secrets 里再加一组凭据。

最终方案:服务器上执行。部署脚本里直接调腾讯云 CDN Purge API,凭据从 .env 文件读取。

一开始用 Python 手写了 TC3-HMAC-SHA256 签名,结果踩了一堆坑——服务器 Python 3.6.8 不支持新语法、shell 转义把签名搞坏、PurgeUrlsCacheFlushType 参数名和文档不一致。后来换成腾讯云官方 Node.js SDK(tencentcloud-sdk-nodejs),几行代码搞定,本地测试一次通过。

变更感知:不是一把梭

最粗暴的做法是每次部署都全站刷新 CDN。但这样太浪费了——改了个页面组件就得刷全站,没必要。

所以我做了一个变更范围检测:

变更路径 CDN 刷新策略
src/components/** 全站 /
src/app/layout.tsx / globals.css 全站 /
src/app/chat/page.tsx 只刷 /chat/
public/** 精确 URL
docs/** / *.md 跳过

GitHub Actions 在 skip-check 阶段已经拿到了 CHANGED_FILESgit diff --name-only HEAD~1 HEAD),把这个列表通过 SSH 环境变量传到服务器,写入临时文件,再交给 purge-cdn.mjs 分析。

实现细节

整个流程是:

复制代码
push → skip-check (获取 CHANGED_FILES)
  → build-and-deploy
    → SSH 部署 (git pull → 写入变更文件 → deploy.sh)
      → purge-cdn.mjs --changed-file /tmp/.deploy_changed_files
        → analyzeChanges() 按规则匹配
          → 精准刷新对应路由
      → rm /tmp/.deploy_changed_files

purge-cdn.mjs 用腾讯云官方 Node.js SDK 调 CDN Purge API,不用手写签名,代码干净可靠。项目本身是 Next.js,服务器有 Node.js,不需要额外装运行时。

一个意外发现

测试的时候发现服务器上居然没有 .env 文件?凭据全在 Docker 容器的环境变量里。最后发现 .env/www/wwwroot/react.nnnnzs.cn/.env,是 docker-compose.prod.ymlenv_file 引用的那个路径。之前 find 命令没找到是因为搜索深度不够。

总结

改动涉及 5 个文件:

  1. src/app/chat/page.tsxexport const revalidate = 3600
  2. scripts/purge-cdn.mjs — 新增,腾讯云 CDN 缓存刷新 + 变更检测(Node.js SDK 版)
  3. scripts/deploy.sh — 新增 purge_cdn 函数
  4. .github/workflows/docker-release.ymlCHANGED_FILES 传递链路
  5. .gitignore — 排除部署临时文件

服务器上跑了一轮测试,API 调用成功,变更检测逻辑正常。下次部署就自动生效了。

这种「部署后自动清理 CDN」的模式,感觉每个用 CDN 的项目都应该有一套。毕竟用户不应该为你的部署流程买单——你更新了,他就应该看到最新的。

加载评论中...