接口返回 SUCCESS,业务却全失败:一次静默鉴权失效的排查记录
这次的问题很典型:一个跑了三个月的签到脚本,某天开始日志里每天都是「完成 ✅」,但账户里的奖励一动不动。表面看一切正常,实际什么都没做。
一、症状:日志说成功,数据说没有
脚本每天的日志长这样:
## 开始执行... 09:01:00
用户【183****8686】 - 签到请求异常!'NoneType' object is not subscriptable
PUSHPLUS 服务启动
## 完成 ✅... 09:01:13 耗时 13 秒
注意它最后还是打了「完成 ✅」——因为异常被 try/except 吞掉了,主流程正常退出,退出码 0。监控看退出码,就永远是绿的。
二、第一次误判:以为 token 过期了
最直觉的猜测是登录态过期。于是直接拿库里的 token 打接口:
curl -X POST https://app.example.cn/welfarecenter/index/signIndex \
-H "phone: 183****8686" -H "apptoken: $TOKEN" -H "device: $DEVICE" \
-H "Content-Type: application/json" -d '{}'
返回:
{"code":2200,"message":"SUCCESS","time":1794106xxxxx,"data":null}
这是整件事最关键的一行。 code 是成功的,message 是 SUCCESS,唯独 data 是 null。脚本的判断是 if data['code'] != 2200: 报错,于是它认为验证通过,继续往下取:
mileage = data['data']['mileageBalance']['mileage']
# data['data'] 是 None → TypeError: 'NoneType' object is not subscriptable
也就是说:服务端用「成功」的外壳装了一个「拒绝」,而客户端只看了外壳。
三、第二层:改了配置却不生效
确认 token 过期后,抓了新的 apptoken 写进数据库。跑一遍——还是同样的报错。这时候容易怀疑「token 是假的」,但单独用 httpx 发同样的请求,返回是正常的:
r = httpx.post(url, headers=h, json={}, verify=False, timeout=40)
print(r.status_code, len(r.text)) # 200 6310 ← 有数据
同一台机器、同一个 token、同一组 header,手写请求成功,脚本请求失败。差别只可能在一个地方:脚本读到的 token 根本不是数据库里那条。
加一行调试打印就露馅了:
print(len(os.getenv("tc_cookie")), os.getenv("tc_cookie")[90:130])
输出的值和我刚写入的完全不是同一条。任务调度器注入环境变量的路径,不是数据库。 它读的是预制脚本 preload/env.sh、env.py、env.js 三份文件——三份都要改,改数据库只是改了个没人读的地方。
四、第三个坑:高频请求被直接 RST
token 修好之后又遇到一次:日志里只有一句空异常「签到请求异常!」,后面什么都没有。httpx 抛出的异常对象 str(e) 是空字符串,这通常是连接被对端重置(RST)。
原因是排查过程中短时间内连续打同一接口。加一层退避重试就稳定了:
async def _post_retry(self, url, body=None, tries=4, wait=6):
last = None
for i in range(tries):
try:
return await self.client.post(url, headers=self.headers, json=body or {})
except Exception as e:
last = e
if i < tries - 1:
await asyncio.sleep(wait * (i + 1)) # 6s / 12s / 18s
raise last
五、三件事,按这个顺序修
- 判空优先于判 code。
if not data or data.get('code') != 2200 or not data.get('data'):—— 三个条件缺一不可。业务字段为空就等于失败,别让外围的成功码骗过去。 - 确认配置真实注入路径。 改完配置,打印一行「读到的值」,比读十遍文档有用。
- 给批量请求加退避。 空消息异常基本都是 RST,重试 3~4 次、间隔递增,比加大 timeout 有效。
结语
这类问题最难的不是技术,是「看起来没问题」。退出码 0、日志有「完成」、监控全绿——但只要业务数据不动,就是没跑。所以判断脚本好坏的标准永远只有一个:结果数据变了没有,不是它自己说自己成功没有。
- 点赞
- 收藏
- 关注作者
评论(0)