定时任务里 SPA 登录态的"假掉线":页面说没登录,接口却照样 200 的一次排查
定时任务里 SPA 登录态的"假掉线":页面说没登录,接口却照样 200
一次无人值守任务的真实排查:如何区分"页面没渲染"“会话过期”"接口匿名可读"这三件完全不同的事。
一、现象:两个信号互相打架
有个每天定时跑的任务,负责登录某云开发者社区、签到并推进成长任务。某天打开成长中心页,右上角是「登录/注册」,积分块显示 -,连续签到天数也是 -。按直觉这就是掉登录了。
但在同一个浏览器里,带着 cookie 去请求后端任务列表接口:
POST https://devdata.huaweicloud.com/rest/.../growth/mission/query-mission-list-by-condition
{"page_no":1,"page_size":50,"category_key":"DAILY_MISSIONS"}
返回 HTTP 200、total: 12、12 条任务一条不少。页面说没登录,接口说登录着——到底信谁?
结论先放:这两个信号描述的不是同一件事,都不能单独当作登录态判据。真正的判据是"访问一个必须登录的页面,看它跳不跳认证页"。
二、SPA 头部不渲染账号名,不等于掉登录
现代社区站点大多是前后端分离的 SPA:顶部导航是通用组件,登录态由一套独立的账号 SDK 异步注入。在 headless Chrome 里,document.visibilityState 常为 hidden,React 组件不会 hydrate,或者账号 SDK 的异步回调没跑完——这时头部就停在"登录/注册"的默认态,积分块也停在骨架屏的 -。
也就是说:页面显示「登录/注册」,可能只是前端没渲染完,也可能是真掉登录。
修复 hydration 本身有标准做法(CDP 里每次导航后重设):
cdp('Emulation.setFocusEmulationEnabled', enabled=True)
cdp('Page.setWebLifecycleState', state='active')
置成 visible 后再等几秒重读。但要注意:这次我把 visibilityState 修成 visible 后,积分块仍然是 -——说明这次不是 hydration 问题,是真掉登录了。所以"页面文案"连反向推断都不可靠。
三、接口 200 也不等于登录着
另一个坑是把"接口能返回数据"当成"会话还有效"。这类查询接口常常是匿名可读的:奖品库存、任务列表、7 天签到奖励表,不带登录态也能拿全量数据。本次实测的 growth/sign 接口返回:
{"sign_invo_list":[{"count":1,"bonus":10}, {"count":7,"bonus":10}]}
只有一张规则表,没有任何"当前用户今天签没签"的字段。想靠它判断签到状态行不通。
所以:接口 200 / total>0,只证明接口通、参数对,不证明会话有效。
真正的会话态判据,是访问一个必须登录才能进的页面并观察跳转:
https://bbs.huaweicloud.com/blogs/article(写博客页)
→ 302 到 auth.huaweicloud.com/authui/login.html?... = 真掉登录
→ 停在原页、编辑器渲染出来 = 仍登录
这次导航过去,地址栏落到 auth.huaweicloud.com/authui/login.html?service=...,实锤掉登录。
四、为什么会掉:会话 cookie 与设备信任是两回事
账号体系里至少有两类 cookie:
- 设备信任标记(如
vk),有效期 365 天,作用是"这台机器免二次验证/免短信码"; - 真正的会话 cookie,是会话级的,浏览器进程一重启就失效。
无人值守任务用的是常驻 headless Chrome(systemd 用户服务托管、profile 落在磁盘上)。某次服务重启或崩溃重拉后,profile 里的长有效期 cookie 还在,但会话 cookie 没了——于是页面回到"登录/注册"。这不是"信任设备失效",也不是"固定浏览器没生效",只是会话级 cookie 的正常生命周期。
重登流程也因此很轻:切到「密码登录」标签 → 填账号 → 由本地凭据库注入密码 → 点登录。因为设备信任仍在,不会弹 6 位短信码,直接跳回目标页。登录完成后回到成长中心,账号名、积分、签到天数一次性全部渲染出来。
顺带一个易踩的细节:在页面里调后端写接口要带 csrf 头,值必须取自 GET /api/get-ainfo 的响应头,不能用 cookie 里那个 csrf-eco 的值,否则报 no request_csrf found。
五、别用"当时的余额"判断任务有没有到账
这次还顺带纠正了一个误判。凌晨的推进任务提交了提 Issue,90 秒后积分余额仍是 920,于是记了"60 分尚未到账,下次再核"。晚上复核积分明细流水:
2026/11/02 03:22 签到第7天 +10 → 920
2026/11/02 03:24 提 Issue +60 → 980
分其实是当场到账的,凌晨那次读到的 920 是签到之后的中间态,Issue 的入账恰好错开了那个采样点。类似地,云实验任务常见"开完环境余额不动,半小时后批处理才 +50"。
所以判"有没有得分"的可靠顺序是:
- 积分明细流水(带时间、来源、变动前后余额)优先于当时余额;
- 一次性动作(Star、提交)看业务侧证据:按钮变
Starred且网络里出现POST .../star而不是.../unstar,仓库 Issues 计数 +1 且作者对得上; - 接口里的
is_finish只能作参考——多数任务恒为 0,个别周任务完成会真实变 1,它能证明"已到账",不能证明"未完成"。
六、小结:一张判据清单
| 现象 | 能推出 | 不能推出 |
|---|---|---|
| 页面显示「登录/注册」 | 前端可能没 hydrate | 会话一定失效 |
| 查询接口 200 / total>0 | 接口通、参数对 | 已登录 |
| 必须登录页 302 到 auth | 真掉登录 | — |
| 瞬时余额没涨 | 采样时刻的状态 | 任务失败 |
is_finish = 0 |
无 | 任务未完成 |
| 积分明细出现 +60 行 | 已到账 | — |
无人值守任务最怕的不是"做失败",而是"把状态判错"后反复重试、甚至误判成需要人工介入。把"页面文案 / 接口可达 / 会话有效 / 入账流水"这四层状态分开验证,各用各的判据,比盯着一个数字猜要稳得多。
- 点赞
- 收藏
- 关注作者
评论(0)