无头CMS内容同步,多终端内容统一更新
无头CMS把内容存储和页面展示拆开了,编辑在后台发布文章后,网站、App、小程序往往不会自动更新,需要手动刷新或等缓存过期。
本文用Strapi为例,讲清楚如何通过Webhook和API让多终端内容统一更新,读完你能独立配好一套自动同步链路。
先理清同步链路和前置条件
无头CMS内容同步的核心逻辑是:内容变更 → 触发通知 → 各终端拉取新数据 → 刷新展示。
你需要在服务器上准备好以下环境:
- 一个运行中的无头CMS,本文以Strapi v4为例,默认端口
1337 - 至少一个前端站点,比如Next.js或Nuxt项目,部署在
/www/wwwroot/frontend - 服务器能执行
curl和node命令,宝塔面板用户可直接用终端 - 如果前端用了CDN,需要拿到CDN的刷新API密钥
先在CMS后台创建一个测试文章,记下它的API地址,比如http://你的IP:1337/api/articles。
在浏览器访问这个地址,能返回JSON数据说明API正常。
配置Webhook让CMS主动通知
Strapi后台自带Webhook功能,路径是设置 → Webhooks → 创建新Webhook。
填写前端接收地址,比如https://你的域名/api/revalidate,勾选entry.create、entry.update、entry.delete三个事件。
保存后,每次发布或修改文章,Strapi就会向这个地址发送POST请求。
前端项目需要写一个接收接口。
以Next.js的pages/api/revalidate.js为例:
import { revalidatePath } from 'next/cache'
export default async function handler(req, res) {
if (req.method !== 'POST') return res.status(405).end()
const secret = req.headers['x-webhook-secret']
if (secret !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ message: '无效密钥' })
}
try {
await revalidatePath('/articles/[slug]', 'page')
return res.json({ revalidated: true })
} catch (err) {
return res.status(500).json({ message: '刷新失败' })
}
}
在Strapi的Webhook设置里添加请求头x-webhook-secret,值和前端环境变量一致。
这样每次内容变更,前端页面会自动重新生成。
用API拉取实现App和小程序同步
网站之外的终端,比如App和小程序,通常不能直接接收Webhook。
更稳的做法是让它们定时调用CMS的API。
在App启动或下拉刷新时请求/api/articles?,按更新时间倒序拿最新数据。
sort=updatedAt:desc
如果数据量较大,建议加一个updatedAt过滤参数,只拉取上次同步之后的内容:
curl -H "Authorization: Bearer 你的API令牌" \
"http://你的IP:1337/api/articles?filters[updatedAt][$gt]=2025-01-01T00:00:00.000Z"
把返回的JSON存到本地数据库或缓存中,界面渲染时直接读本地数据。
这样即使CMS临时不可用,App也能展示上次同步的内容。
缓存刷新和避坑要点
CDN缓存是最容易被忽略的一环。
前端页面更新了,但CDN还返回旧内容,用户看到的仍然是旧文章。
宝塔面板用户可以在网站 → CDN中配置刷新,或者调用CDN厂商的刷新接口:
curl -X POST "https://cdn.example.com/refresh" \
-H "Authorization: Bearer 你的CDN密钥" \
-d '{"urls":["https://你的域名/articles/测试文章"]}'
几个常见坑:
- Webhook地址必须公网可访问,本地
localhost收不到请求 - 密钥不要写在前端代码里,用环境变量存储
- Strapi默认权限可能禁止公开读取,需要在
设置 → 用户与权限 → 角色中给Public角色勾选find和findOne - 循环触发:前端刷新页面时又调用了CMS写接口,会导致无限循环,务必让接收接口只读不写
验证同步是否真正生效
改一篇测试文章的标题,保存后观察三个地方:网站页面标题是否变化、App下拉刷新后是否显示新标题、CDN缓存是否命中新内容。
如果网站变了但App没变,检查App的API请求是否带了updatedAt过滤条件;
如果都没变,去Strapi的Webhook日志里看请求是否成功发出。
整个链路跑通后,日常发布内容只需要在CMS后台点一次保存,所有终端会在几秒到几分钟内自动更新。
建议先用测试文章验证,确认无误再应用到正式内容。
常见疑问
Webhook和定时轮询哪个更好?
Webhook实时性高,适合网站这类能接收请求的终端;轮询实现简单,适合App和小程序。两者可以同时用,互不冲突。
Strapi重启后Webhook会丢失吗?
Webhook配置存在数据库中,重启不会丢失,但需要确认数据库连接正常。
前端刷新接口返回401怎么排查?
先检查请求头里的密钥是否和前端环境变量一致,再确认Strapi Webhook的请求头名称有没有拼错,大小写敏感。