接口突然 404:先分清是登录过期还是服务端变了
一个每天在跑的脚本,某天突然开始报错:接口返回 404。第一反应通常是「Cookie 过期了」,于是去重新登录、换一份凭证。但有时候换了还是 404,说明根本不是登录的问题。
这篇记一下这类问题的排查顺序。它不是某一次的经验,是每次遇到都值得按顺序走一遍的流程。
一、先把「404」拆成三种
同样是 404,来源完全不同:
1. 业务接口自己的 404:路径写错、资源不存在,返回体通常是 JSON,比如 {"message":"no Route matched with those values"}。 2. 网关或防护层的 404:请求根本没到业务服务,被 WAF 拦下,返回的是 HTML。 3. 登录失效被重定向:服务端把你 302 到登录页或错误页,客户端跟随后拿到的状态码变成 200 或 404。
第三种最容易被误判,因为大多数 HTTP 客户端默认自动跟随重定向。你在代码里看到的是最终状态码,看不到中间那一跳。
二、第一件事:关掉自动重定向,看真实的响应
用 curl 最直接,因为它默认不跟随:
curl -s -D - -o /dev/null \
-H "Cookie: $CK" \
https://example.com/api/something
如果返回 HTTP/2 302 加一个 location: /common/404.html,那说明请求被挡在业务层之前,跟业务代码没有关系。这时候去查接口路径、参数都是白费功夫。
这一步的价值在于:它把「我的代码错了」和「对端不让我进」分开了,而这两种情况后面的排查方向完全相反。
三、第二件事:变量一次只改一个
确认是防护层拦截之后,问题就变成了「它凭什么拦我」。请求里能影响判定的东西不多:
- Cookie(是否登录、有没有反爬标记)
- User-Agent
- Referer 与 Origin
- 请求方法、Content-Type
- 来源 IP
用同一份 Cookie 逐个加头测试,很快就能定位。我这次遇到的情况是 UA:
# 302 到 /common/404.html
UA='... Chrome/155.0.0.0 Safari/537.36'
# 200,正常返回
UA='... Chrome/157.0.0.0 Safari/537.36'
原因是防护规则更新了浏览器的版本白名单,把旧版本当成了可疑客户端。代码没有任何改动,但它每天都在变——这类问题只能靠比对定位,不能靠读代码想出来。
四、第三件事:留意「哪一跳变红的」
一个请求链路上通常有好几个服务:网关、鉴权、业务。返回值一样是 404,但来源不同,处理方式也不同。
判断方法很简单:看响应头。
server: CloudWAF
content-type: text/html
有 server 是防护层、content-type 是 HTML,说明没进业务。如果返回的是 JSON、还带着业务错误码(比如 HD.xxx),那就是业务层的问题,该查参数查参数。
多花十秒看响应头,能省掉半小时的瞎猜。
五、把结论写进代码注释
定位完以后,值得把原因写进代码里那一行旁边,而不是只留在脑子里:
// UA 版本被 WAF 卡过:Chrome/155 会 302 到 /common/404.html,改 157 才放行。
ua = "Mozilla/5.0 ... Chrome/157.0.0.0 Safari/537.36"
理由很实际:这个问题半年后会以另一种形式回来。到时候你会记得「之前遇到过类似的事」,但想不起是哪一项、为什么。注释是唯一可靠的地方,提交信息不会有人去翻。
六、小结
排查顺序:关掉重定向看真实状态码 → 确认是业务 404 还是防护 404 → 按单个变量比对请求头 → 把结论写进注释。
整个过程不需要读代码,因为问题往往不在代码里。这也是这类问题最烦人的地方:昨天还能跑的东西今天不能跑,而你的仓库一个提交都没有。
- 点赞
- 收藏
- 关注作者
评论(0)