设备环境:iPad Pro 2021,iPadOS 18
问题描述:页面有一个菜单接口没有请求,但菜单仍能显示,且数据不正确。
由于请求需要通过客户端中转,加上 Web 页面本身存在 iframe 父子页面结构,排查起来比较复杂。
排查过程中发现了一系列诡异的现象:
✅在这台 iPad 上出现,其他安卓、iPhone 无问题
✅在测试环境有问题,在本地开发地址无问题
✅因为怀疑页面缓存什么的,就切换预发布地址尝试,也是有问题,再切回测试地址,还是有问题。
✅甚至其他 iPad 也无问题
✅重新安装包测试仍有问题
const now = Date.now()const wait = 3000const lastFetchTime = parseInt(Local.get('lastFetchTime')) || 0if (now - lastFetchTime < wait) {// 取缓存数据return}// 否则,存储请求时间、请求接口Local.set('lastFetchTime', now.toString())fetch()
问题就出在这里:lastFetchTime是一个未来的时间戳!
这导致now - lastFetchTime < wait永远成立(负数必然小于 3000),所以页面始终使用缓存数据,从不发起真正的请求。
if (now > lastFetchTime && now - lastFetchTime < wait) {// 取缓存数据return}
至此,所有诡异的现象都能解释了:
1. 为什么只有测试环境有问题?
localStorage 是按域名隔离存储的:
测试环境和预发布环境域名相同,共享同一份 localStorage
本地开发地址和生产地址与测试地址域名不同,各自独立
测试同学修改系统时间时,正好在测试环境域名下写入了那个「未来时间戳」。
2. 为什么重装 App 也不行?
这里发现了一个 iOS 的特性:iOS WebView 的 localStorage 无法通过重装 App 清除。具体原理尚不清楚,但实测确实如此。这解释了为什么换包测试问题依旧存在。
3. 为什么现在才发现?
因为「巧合」太多了:
测试修改系统时间时,恰好缓存了一份错误的菜单数据(比如红点状态不对)
如果缓存的数据碰巧是正确的,即使走了缓存逻辑,也不会暴露问题
多个巧合叠加,导致这个 Bug 潜伏了很久才被发现。
为什么排查花了这么久?
菜单相关的代码很久没看了,一时忽略了历史实现细节
问题表现太诡异——只在特定设备出现,同型号都无法复现,而且不是账号数据问题
数据通信经过客户端中转,增加了对调试复杂度的心理预期
这个问题一开始看起来十分诡异,但一旦定位到原因,又觉得确实是代码问题。事后来看,至少是可以一步步排查的。
遇到奇怪的问题,不要放过——看起来无法排查的问题,往往还是可以尝试的
久远的代码逻辑,先梳理一遍——不要想当然地跳过
任何现象都有原因——既然没请求接口但有数据显示,那数据一定来自某处,顺着这个思路排查
培养不依赖调试、直接读代码推理的能力——特别是在无法调试的场景下
多确认用户操作——这次如果早点问测试「有没有改过系统时间」,可能会更快定位问题