mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-27 16:26:16 +08:00
Enrich Codex proxy forwarding-error responses with context
When forward_with_retry fails for Codex endpoints (/chat/completions, /responses, /responses/compact), the handlers previously returned the bare ProxyError, surfacing a terse body to the client. Build a richer JSON error instead: the message embeds provider, model, endpoint and upstream status, and the error object carries those as structured fields alongside a stable cc_switch_* code. Align map_proxy_error_to_status with ProxyError::into_response so the manually built responses use the canonical status codes (AuthError->401, Config/InvalidRequest->400, TransformError->422, StreamIdleTimeout->504, AlreadyRunning->409, NotRunning->503); previously these forwarder-level errors collapsed to 500.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
//! 错误类型到 HTTP 状态码的映射
|
||||
//!
|
||||
//! 将 ProxyError 映射到合适的 HTTP 状态码,用于日志记录
|
||||
//! 将 ProxyError 映射到合适的 HTTP 状态码,用于日志记录和手动构建错误响应
|
||||
|
||||
use super::ProxyError;
|
||||
|
||||
@@ -12,14 +12,21 @@ use super::ProxyError;
|
||||
/// - 连接失败:502 Bad Gateway
|
||||
/// - 无可用 Provider:503 Service Unavailable
|
||||
/// - 重试耗尽:503 Service Unavailable
|
||||
/// - 认证错误:401 Unauthorized
|
||||
/// - 配置/请求错误:400 Bad Request
|
||||
/// - 转换错误:422 Unprocessable Entity
|
||||
/// - 其他错误:500 Internal Server Error
|
||||
pub fn map_proxy_error_to_status(error: &ProxyError) -> u16 {
|
||||
match error {
|
||||
// 服务状态错误:与 IntoResponse 保持一致
|
||||
ProxyError::AlreadyRunning => 409,
|
||||
ProxyError::NotRunning => 503,
|
||||
|
||||
// 上游错误:使用实际状态码
|
||||
ProxyError::UpstreamError { status, .. } => *status,
|
||||
|
||||
// 超时错误:504 Gateway Timeout
|
||||
ProxyError::Timeout(_) => 504,
|
||||
ProxyError::Timeout(_) | ProxyError::StreamIdleTimeout(_) => 504,
|
||||
|
||||
// 转发失败/连接失败:502 Bad Gateway
|
||||
ProxyError::ForwardFailed(_) => 502,
|
||||
@@ -39,11 +46,17 @@ pub fn map_proxy_error_to_status(error: &ProxyError) -> u16 {
|
||||
// Provider 不健康:503 Service Unavailable
|
||||
ProxyError::ProviderUnhealthy(_) => 503,
|
||||
|
||||
// 配置错误/无效请求:400 Bad Request
|
||||
ProxyError::ConfigError(_) | ProxyError::InvalidRequest(_) => 400,
|
||||
|
||||
// 认证错误:401 Unauthorized
|
||||
ProxyError::AuthError(_) => 401,
|
||||
|
||||
// 数据库错误:500 Internal Server Error
|
||||
ProxyError::DatabaseError(_) => 500,
|
||||
|
||||
// 转换错误:500 Internal Server Error
|
||||
ProxyError::TransformError(_) => 500,
|
||||
// 转换错误:422 Unprocessable Entity
|
||||
ProxyError::TransformError(_) => 422,
|
||||
|
||||
// 其他未知错误:500 Internal Server Error
|
||||
_ => 500,
|
||||
@@ -104,6 +117,30 @@ mod tests {
|
||||
assert_eq!(map_proxy_error_to_status(&error), 503);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_map_status_matches_proxy_error_response_semantics() {
|
||||
assert_eq!(
|
||||
map_proxy_error_to_status(&ProxyError::AuthError("bad token".to_string())),
|
||||
401
|
||||
);
|
||||
assert_eq!(
|
||||
map_proxy_error_to_status(&ProxyError::ConfigError("bad config".to_string())),
|
||||
400
|
||||
);
|
||||
assert_eq!(
|
||||
map_proxy_error_to_status(&ProxyError::InvalidRequest("bad request".to_string())),
|
||||
400
|
||||
);
|
||||
assert_eq!(
|
||||
map_proxy_error_to_status(&ProxyError::TransformError("bad transform".to_string())),
|
||||
422
|
||||
);
|
||||
assert_eq!(
|
||||
map_proxy_error_to_status(&ProxyError::StreamIdleTimeout(30)),
|
||||
504
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_error_message() {
|
||||
let error = ProxyError::UpstreamError {
|
||||
|
||||
Reference in New Issue
Block a user