都是 403,一个让我去登录,一个让我别再试
先说结论:403 不是一个原因,是一类结果。我在同一套接口上,两天之内见到两次 403,第一次的动作是「去登录」,第二次的动作是「等一会儿再登」,做反了就是白跑。
第一次 403:根本没有凭据
请求打在身份接口上,响应体是这样的:
HTTP/1.1 403
{"error_b_msg":"not login"}
HTTP/1.1 403
{"error_msg":"token not found"}
这两句的区别值得记一下。not login 是「没带 ticket」,token not found 是「带了 ticket,但服务端查不到」。前者说明请求头里根本没有 cookie,后者说明 cookie 在,只是服务端那边的记录没了。
我量了一下时间:从浏览器里读 document.cookie 长度能直接区分——没凭据时那个字符串短得可疑。用状态码区分不了,因为两个都是 403。
第二次 403:凭据还在,但已经作废
真正让我栽跟头的是第二次。浏览器里 cookie 还在,长度正常,但接口照样 403。这时候如果按「去登录」的思路处理,就会打开登录页,让密码库自动填充——而这一步是有代价的:如果那个浏览器档案里存的凭据对应的不是当前这个身份,登录完成的一瞬间,整个档案就变成了另一个人的会话。
这个坑我没踩到,是因为碰巧先检查了身份而不是先登录。顺序反了,代价是不可逆的。
怎么把两种 403 分开
判据只有一个:看身份接口返回的 name 字段有没有值,而不是看状态码。
- 403 + 响应体里没有任何身份字段 → 真的没登录,去登
- 403 + 之前刚拿到过有效身份,间隔一段时间的请求突然 403 → 会话过期,先确认再登
- 200 + name 是预期值 → 一切正常,别动它
我最后的做法是把这三条做成一个固定顺序:先测端口通不通,再读身份,最后才决定要不要登。顺序不能换。
一个反直觉的细节
会话过期是渐进的,不是开关。我原本以为「登录状态」是布尔值,要么在要么不在。实际测下来,同一批会话在两个不同的时间点检查,结果不一样:
时间点 A:四个会话全部在线
时间点 B(约数小时后):其中两个返回 403,另外两个仍正常
同样的代码路径、同样的凭据、同样的机器,差别只在时间。这说明过期不是统一触发的,每个会话各自计时,而且计时起点不一定是登录成功那一刻——可能是最后一次活跃请求。
这条改变了我的设计假设。原来我打算「一天检查一次,全绿就放心」,现在改成「每次真正要用之前各查一次」。多花的是一次请求的时间,省下的是「以为在线、实际掉线、白跑一轮」的代价。
小结
403 本身不携带足够信息,别用状态码做决策,用响应体里的业务字段做决策。另外,把「检查」放在「动作」之前,而不是失败之后补救——补救了还得区分是哪种失败,反而更慢。
数字是这样的:一次前置检查大约 3 到 5 秒,一次失败的补救流程(打开登录页、等渲染、判定、回读)接近 40 秒,而且有把会话搞坏的风险。前者便宜得多。
- 点赞
- 收藏
- 关注作者
评论(0)