Cloudflare 部署无报错,但移动端与 Web 数据不同步,如何排查?
结论:先追踪一次修改的完整路径
“部署成功、控制台无报错”不足以判断问题出在 Cloudflare 缓存、持久化还是 session。部署成功说明部署流程完成,但不能证明业务数据已经保存,也不能证明另一台设备会主动读取更新。
可以用一条测试记录追踪完整路径:
设备 A 修改 → 发出保存请求 → 后端完成写入 → 设备 B 发出读取请求 → 返回新数据 → 页面显示新数据
“强制刷新后有时恢复”提示需要检查读取时机和缓存,但还不足以认定问题出在 edge cache。
1. 确认修改是否真的离开了设备 A
在设备 A 的开发者工具中打开 Network,保留请求记录,然后修改一条容易识别的测试笔记。检查:
- 是否发出了对应的保存请求,例如
POST、PUT或PATCH。 - 请求中的记录 ID 和修改内容是否正确。
- 请求实际发往哪个 API 地址。
- 响应正文是否表示业务保存成功,而不只是 HTTP 状态码为
200。
如果没有保存请求,检查代码是否只更新了页面内存、localStorage 或 IndexedDB。这些本地状态本身不会跨设备同步。还要确认是否存在尚未执行的防抖保存、离线队列或被忽略的异常。
如果请求已经发出,继续到后端核对写入结果。页面立即显示修改可能只是乐观更新,不能证明数据已经持久化。
2. 核对持久化位置和用户身份
找到保存接口实际执行的写入操作,确认数据存在哪里。如果后端只把笔记放进 Worker 模块级变量、数组或 Map,就不能依靠它们实现可靠的跨请求持久化。Workers 不保证两次请求进入同一个实例,实例也可能被回收。参见 Workers 执行模型。
如果已经使用数据库或其他持久化服务,应核对:
- 保存接口与读取接口是否连接同一个数据库、namespace 和部署环境。
- 写入是否确实完成;需要保存完成后再返回成功的接口,是否正确等待了写入结果。
- 两台设备是否对应同一个后端用户 ID、工作区 ID 和记录 ID。
访问同一个页面 URL 不代表访问同一份业务数据。两台设备可能使用不同的匿名 session,前端也可能调用不同的 API 地址。session token 不同可以是正常情况,需要确认后端是否把它们映射到同一个业务账号。
如果没有登录或设备关联机制,数据又按设备生成的匿名 ID 保存,就需要先明确如何跨设备共享同一份数据。
3. 在设备 B 区分“没读取”和“读到了旧数据”
设备 A 保存后,先不要刷新设备 B,观察它是否发出了读取请求。
| 观察结果 | 下一步检查 |
|---|---|
| 没有读取请求 | 页面是否实现轮询、重新聚焦时读取或服务端推送 |
| 请求返回旧数据 | 用户身份、存储位置、读取条件和缓存 |
| 请求返回新数据,页面仍显示旧内容 | 前端状态更新、客户端数据缓存,以及旧请求是否覆盖新结果 |
| 刷新后仍返回旧数据 | 回查写入结果和读取链路,不能只清浏览器缓存 |
即使后端已经保存,另一台设备上的页面也需要重新请求或接收通知,才能显示变化。
下面的代码可在同源页面的浏览器控制台中辅助检查读取响应。/api/notes 只是示例,必须替换成实际的读取接口:
async function inspectNotes() {
const response = await fetch('/api/notes', {
credentials: 'same-origin',
cache: 'no-store'
});
const body = await response.text();
console.log({
status: response.status,
cacheControl: response.headers.get('cache-control'),
cfCacheStatus: response.headers.get('cf-cache-status'),
age: response.headers.get('age'),
body
});
if (!response.ok) {
throw new Error(`Read failed: HTTP ${response.status}`);
}
}
inspectNotes().catch(console.error);
这个示例适用于使用同源 Cookie 认证的接口。如果应用使用 Bearer token 或跨域 API,应按实际认证方式调整。cache: 'no-store' 用于排查浏览器 HTTP 缓存,不能保证绕过 Service Worker、自定义 CDN 缓存规则或后端缓存。
4. 用响应证据判断缓存在哪一层
检查笔记 API 的响应,而不只是页面 HTML。观察 Cache-Control、CF-Cache-Status、Age,以及 Network 中是否显示响应来自浏览器缓存或 Service Worker。
Cloudflare CDN 默认不缓存 HTML 或 JSON,但 Cache Rules 和 Worker 中的自定义缓存逻辑可能改变实际行为。因此,不能仅凭应用部署在 Cloudflare 上就认定 API 被边缘缓存。参见 默认缓存行为。
可以逐层做对照:
- 在开发者工具中启用 Disable cache,重新请求同一条记录。
- 如果应用注册了 Service Worker,临时启用网络绕过,再比较响应。
- 检查匹配 API 路径的 Cache Rules,以及代码中是否使用 Cache API 或框架缓存。
- 对需要每次读取最新值的个人数据接口,检查是否适合返回
Cache-Control: private, no-store,并确认没有其他规则强制缓存。
CF-Cache-Status: HIT 是检查该响应缓存路径的线索;没有这个响应头,也不能排除应用内部缓存。每次只改变一个条件,记录响应内容是否变化,才能知道哪个设置产生了影响。
如果实际使用的是 Workers KV,还要单独考虑它的最终一致性:其他网络位置可能暂时读取到旧值,这与浏览器缓存或 HTTP edge cache 是不同的问题。确认使用 KV 后,再沿这个方向调查。参见 KV 一致性说明。
5. 为保存和读取过程添加日志
浏览器控制台看不到 Worker 内部的全部执行过程。如果后端使用 Workers,可在对应项目中确认目标部署环境,再运行:
npx wrangler tail
随后重新执行一次保存和读取,观察服务端日志。也可以通过 Cloudflare 控制台查看实时日志。命令及使用方式见 Workers 实时日志说明。如果使用 Pages Functions,应选择对应部署的 Functions 日志入口。
建议在保存和读取接口记录请求 ID、操作类型、内部用户 ID、记录 ID、目标存储标识,以及写入结果或读出的版本号。如果应用目前没有版本字段,不要假定它存在,可以先通过测试记录的唯一内容核对。避免记录 Cookie、token 和完整笔记正文。
还要检查是否存在 catch 后返回空列表、忽略写入失败或始终返回成功的代码。这些处理会让故障表现为“没有报错,但数据不对”。
排查时应明确断点,例如“保存请求未发出”“两端用户 ID 不同”或“读取响应已更新但页面状态未更新”。找到断点后,再修改对应的保存、认证、缓存或刷新逻辑。
备注:内容仅供参考。
