登录路由的429归业务变体

- map_auth_failure 的 429 改为按路由判定:SendCode 仍是 SmsCodeThrottled,PhoneLogin 映射为 PhoneCodeLoginRejected(用户可修正、不进错误池),其余路由才落 UnexpectedRejection
- 补用例覆盖登录 429 与其它路由 429;map_auth_failure 注释同步新口径
This commit is contained in:
2026-10-02 11:50:43 +08:00
parent f8c32e6346
commit b54b3794f6
@@ -501,7 +501,8 @@ fn auth_route(route: &str) -> AuthRoute {
///
/// 会话路由的 `401/403` 归到权威失效变体,调用方据此清会话;登录路由的 `401` 是用户可修正的
/// 输入问题。可判定的用户输入原因只进业务变体,认不出的才落到 `UnexpectedRejection`。
/// 网络、5xx 与契约异常必须保留会话。
/// `429` 也按路由判定:发码路由是频控,登录路由是「验证码错误次数过多」,两者都是用户可修正的
/// 输入问题;其余路由的 `429` 仍按未识别拒绝处理。网络、5xx 与契约异常必须保留会话。
fn map_auth_failure(status: StatusCode, body: &str, route: AuthRoute) -> ClientAuthError {
crate::platform_maintenance::watch_platform_response(status.as_u16(), body);
let status_code = status.as_u16();
@@ -526,8 +527,17 @@ fn map_auth_failure(status: StatusCode, body: &str, route: AuthRoute) -> ClientA
}),
};
}
if status == StatusCode::TOO_MANY_REQUESTS && route == AuthRoute::SendCode {
return ClientAuthError::SmsCodeThrottled;
if status == StatusCode::TOO_MANY_REQUESTS {
return match route {
AuthRoute::SendCode => ClientAuthError::SmsCodeThrottled,
AuthRoute::PhoneLogin => {
ClientAuthError::PhoneCodeLoginRejected(PhoneCodeLoginRejected { server_message })
}
_ => ClientAuthError::UnexpectedRejection(UnexpectedRejection {
status: status_code,
server_message,
}),
};
}
if status == StatusCode::BAD_REQUEST {
return match route {
@@ -1350,6 +1360,33 @@ mod tests {
);
assert_eq!(throttled, ClientAuthError::SmsCodeThrottled);
// 登录路由的 429 是「验证码错误次数过多」:用户可修正的输入问题,不能进系统变体被上报。
let verify_attempts_exceeded = map_auth_failure(
StatusCode::TOO_MANY_REQUESTS,
r#"{"error":{"message":"验证码错误次数过多,请重新获取验证码"}}"#,
AuthRoute::PhoneLogin,
);
assert_eq!(
verify_attempts_exceeded,
ClientAuthError::PhoneCodeLoginRejected(PhoneCodeLoginRejected {
server_message: Some("验证码错误次数过多,请重新获取验证码".to_string()),
})
);
// 其余路由的 429 仍未识别拒绝:既不冒充业务原因,也不冒充发码频控。
let unknown_throttle = map_auth_failure(
StatusCode::TOO_MANY_REQUESTS,
r#"{"error":{"message":"限流"}}"#,
AuthRoute::Other,
);
assert_eq!(
unknown_throttle,
ClientAuthError::UnexpectedRejection(UnexpectedRejection {
status: 429,
server_message: Some("限流".to_string()),
})
);
let bad_code = map_auth_failure(
StatusCode::UNAUTHORIZED,
r#"{"error":{"message":"验证码错误"}}"#,