页面「自己不停刷新」怎么查?一次 SPA 重定向死循环的完整定位过程

举报
yd_261373198 发表于 2026/10/25 22:07:14 2026/10/25
【摘要】 从证伪自动化、量化 timeOrigin、二分定位到固化修复,完整复盘一次单页应用无限重载的排查过程。

页面“自己不停刷新”怎么查?一次 SPA 重定向死循环的完整定位过程

浏览器自动化跑久了,最容易遇到一类看起来像灵异事件的问题:**窗口里的页面明明没人动,却每隔三四秒整个重新加载一次**。用户的第一反应是"你的程序在刷我的屏",而你的代码里根本没有 `reload()`。

我最近就在华为云成长中心的自动化上踩了一次,本文把定位过程完整写出来——不涉及任何业务细节,方法对所有 SPA(单页应用)通用。

## 一、先证伪:到底是谁在刷新

第一步永远是把"谁干的"这个问题拆成两个可验证的假设:

- 假设 A:我的自动化脚本在反复导航;
- 假设 B:页面自己(或它依赖的某个东西)在反复导航。

证伪 A 的成本极低,一条命令就够:

```bash
pgrep -a geckodriver   # 自动化驱动进程
pgrep -af "venv/bin/python"  # 你自己的自动化脚本
```

如果两个都是空,说明当前没有任何程序在向浏览器发指令,那刷新一定来自页面侧或浏览器侧。**这一步必须先做**,否则你会在自己的代码里找半天,最后发现和白写的一样。

## 二、量化"刷新":用 performance.timeOrigin 打点

"我感觉它在刷"不是证据。真正的证据是导航时间戳。

页面每次重新加载,`performance.timeOrigin` 都会变成新的值;同一个文档内做 SPA 路由切换(`history.pushState`)时它**不会变**。所以只要周期性采样这个值,就能区分"整页重载"和"前端路由跳转":

```python
prev = None
for i in range(6):
    v = driver.execute_script("return String(performance.timeOrigin)")
    print(i, v, "RELOAD" if prev and v != prev else "stable")
    prev = v
    time.sleep(4)
```

我第一次跑出来的结果是:

```
0 1792931810234 stable
1 1792931814373 RELOAD
2 1792931818052 RELOAD
3 1792931822090 RELOAD
...
```

每 3.9 秒一次整页重载。到这一步,"确实在刷新"和"刷新间隔约 4 秒"都成了客观事实,而不是感受。

再补一个更强的信号——导航条目数量:

```javascript
performance.getEntriesByType('navigation').length  // 当前文档的导航次数,重载后重新计数
```

配合采样,你会看到 `1` 与 `2` 交替出现,说明文档在换。

## 三、二分定位:换页面、换配置、换 profile

确认是页面侧重载后,用最小变量法二分。我按这个顺序做的:

第 1 刀:换一个无关页面。 同一浏览器实例打开 `about:blank` 或任意静态页,再采样。如果稳定,说明浏览器本身没毛病,问题出在那个站点的会话状态或路由逻辑上。

我的结果是 `about:blank` 稳定 28 秒不变——浏览器是干净的。

第 2 刀:换 URL 参数。 把带 `?service=xxx` 的登录页换成不带参数的裸登录页。如果仍然刷新,说明不是参数问题。

第 3 刀:清会话状态。 停掉浏览器,把 `cookies.sqlite`、`cookies.sqlite-wal`、`sessionstore-backups/` 全部移走(**移动,不要删**,随时要能回滚),再启动。

这三刀之后我这边页面就稳定了。回头看,根因是两个因素叠加:

1. 会话恢复把三个旧标签全拉回来了。 profile 里 `browser.startup.page=3`(恢复上次会话),而上次会话残留了 3 个页面:grow 页、登录页、以及一个卡在 SSO 中间的页。这三个标签各自在自己的重定向链里打转,切换时看上去就像整个窗口在不停刷新。
2. 半失效的 SSO cookie 造成重定向死循环。 cookie 里有 `cbc-sid` 这类会话标识,但配套的 SSO 状态已过期,于是访问登录页时被弹到 `oauth-login1.cloud.huawei.com/.../loginCallback`,callback 处理失败又弹回 `auth.huaweicloud.com/authui/login.html`,每轮约 4 秒。

## 四、为什么"每 4 秒"这个数字值得注意

重定向死循环不是随机的,它有个稳定的周期。这个周期通常由三部分构成:

- 服务端返回 302 的往返延迟(几十到几百毫秒);
- 前端框架启动、拉取配置、判断登录态的耗时(几百毫秒到 2 秒);
- 某些站点在失败后加了固定延时重试(例如 2 秒后再试一次)。

三者相加就是观测到的 4 秒。**看到一个稳定周期,基本可以判定是代码里的循环逻辑,而不是网络抖动**——网络抖动不会有这么整齐的节奏。

## 五、顺带排掉的两个嫌疑人

定位过程中我还顺手验证了两个常见嫌疑,虽然不是本次根因,但值得记录:

嫌疑人一:浏览器扩展。 日志里出现了大量

```
JavaScript warning: moz-extension://941e4b92-.../content.js, line 10: Script terminated by timeout
```

某个扩展的内容脚本在每个页面上反复执行并超时。这类扩展(自动刷新、广告拦截、脚本管理器)完全有可能主动触发导航。验证方式是启动参数里禁用扩展,或直接把 `extensions.json` 里对应条目的 `active` 置为 `false`(记得先备份)。

嫌疑人二:页面自身的 meta refresh 或定时器。 直接抓 HTML 看不到,因为现代站点都是 JS bundle 渲染的:

```bash
curl -sL site/login.html | grep -iE "http-equiv=\"refresh\"|location\.reload"
```

抓不到只能说明"不在首屏 HTML 里",不能排除 bundle 里有——所以最终还是要在运行时采样 `timeOrigin` 来定论。

## 六、把修复做成不可复发

找到根因只是第一步,更难的是让它不再复发。我最后落了三件事:

1. **关掉会话恢复**:`browser.startup.page=0`,启动时永远是干净的空白页,由脚本显式导航。会话恢复在自动化场景里纯属负资产——你不需要"上次浏览到哪儿",你需要确定性的初始状态。
2. **配置文件级隔离**:自动化用独立的 `-profile` 目录,与日常浏览器完全物理隔离。这样清理 cookie、禁用扩展、改 prefs 都不会影响任何人正在用的窗口。
3. **清理动作可回滚**:cookie、sessionstore、extensions.json 一律 `mv` 到带时间戳的备份目录,而不是 `rm`。线上排障最忌讳"修好了但不知道改了什么、也回不去"。

另外补一个操作纪律:**不要在排障过程中反复重启浏览器**。我一开始就是每次检查登录态都去 `get()` 一下目标页,用户正在输入密码的窗口被重载了四五次,体验极差。正确做法是——需要用户输入时,把窗口摆好就彻底放手,只在用户说"好了"之后再读一次状态。

## 七、可复用的排查清单

把整件事压缩成一张表,下次遇到"页面自己在刷"直接照着走:

| 步骤 | 命令 / 脚本 | 判断依据 |
|---|---|---|
| 1. 证伪自动化 | `pgrep -a geckodriver`、`pgrep -af python` | 空 = 不是我 |
| 2. 量化刷新 | 采样 `performance.timeOrigin` | 值变化 = 整页重载 |
| 3. 换页面 | 打开 `about:blank` 采样 | 稳定 = 站点/会话问题 |
| 4. 换 URL | 去掉 `?service=` 等参数 | 仍刷 = 非参数问题 |
| 5. 清状态 | 移走 cookies / sessionstore | 稳定 = 状态污染 |
| 6. 禁扩展 | `extensions.json` 置 `active:false` | 日志里有 content.js 超时尤其要看 |
| 7. 固化 | `browser.startup.page=0` + 独立 profile | 防复发 |

## 小结

"页面自己在刷新"这类问题,难点从来不是修复,而是**取证**。一旦你能用 `performance.timeOrigin` 把"刷新"变成带时间戳的事实,再用换页面、换 URL、清状态三刀二分,根因通常十分钟内就能锁定。

顺带一句:这次真正让问题恶化的不是 bug 本身,而是我在排障时反复重载了用户正在操作的窗口。自动化脚本的每一次 `get()` 都是一次对用户界面的破坏性操作——**能给用户留一个安静窗口的时候,就别碰它。**

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。