15 KiB
15 KiB
HTTP结果模型
**本文引用的文件** - [http_result.rs](file://crates/shared_types/src/model/http_result.rs) - [app_error.rs](file://crates/shared_types/src/model/app_error.rs) - [lib.rs](file://crates/shared_types/src/lib.rs) - [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs) - [router.rs(rcoder)](file://crates/rcoder/src/router.rs) - [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs) - [router.rs(agent_runner)](file://crates/agent_runner/src/router.rs) - [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs) - [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)目录
简介
本文件围绕HTTP结果模型展开,重点说明统一响应格式的设计理念、成功与失败路径的处理逻辑,并结合Axum处理器的返回类型使用,系统性地介绍HttpResult泛型结果类型与AppError错误体系。文档同时梳理错误码与触发条件、错误上下文信息收集机制、序列化输出示例以及客户端错误处理建议,帮助开发者在不同服务中一致地构建标准化API响应。
项目结构
- 共享类型位于 crates/shared_types,其中定义了HttpResult与AppError等跨服务通用模型。
- rcoder与agent_runner两个服务各自实现了Axum路由与处理器,广泛采用HttpResult作为成功响应,AppError作为错误响应。
- 通过lib.rs统一导出共享类型,便于服务间复用。
graph TB
subgraph "共享类型"
SR["shared_types/lib.rs<br/>统一导出"]
HR["model/http_result.rs<br/>HttpResult<T>"]
AE["model/app_error.rs<br/>AppError 错误体系"]
end
subgraph "rcoder 服务"
RR["rcoder/router.rs<br/>路由注册"]
RH["rcoder/handler/agent_status_handler.rs<br/>处理器示例"]
end
subgraph "agent_runner 服务"
AR["agent_runner/router.rs<br/>路由注册"]
AH["agent_runner/handler/agent_status_handler.rs<br/>处理器示例"]
end
SR --> HR
SR --> AE
RR --> RH
AR --> AH
RH --> HR
AH --> HR
RH --> AE
AH --> AE
图表来源
- lib.rs
- http_result.rs
- app_error.rs
- router.rs(rcoder)
- agent_status_handler.rs(rcoder)
- router.rs(agent_runner)
- agent_status_handler.rs(agent_runner)
章节来源
核心组件
- HttpResult:统一的成功/失败响应载体,包含业务字段code、message、data、tid以及运行时计算的success布尔值。成功路径通过success(data)构造,失败路径通过error(code, message)或internal_error(message)构造。序列化时自动注入success字段,Axum IntoResponse实现负责HTTP状态码与Content-Type设置。
- AppError:统一的错误类型,封装anyhow、IO与通用错误,提供generic、internal_server_error、validation_error等便捷构造方法。其IntoResponse实现将错误标准化为包含error.code与error.message的对象,状态码固定为500。
章节来源
架构总览
下图展示了Axum处理器与统一响应模型之间的交互关系,以及错误路径与成功路径的分流。
sequenceDiagram
participant C as "客户端"
participant R as "Axum 路由"
participant H as "处理器"
participant S as "业务逻辑"
participant OK as "HttpResult<T>"
participant ERR as "AppError"
C->>R : "HTTP 请求"
R->>H : "调用处理器"
H->>S : "执行业务逻辑"
alt "成功"
S-->>H : "返回数据"
H->>OK : "构造 HttpResult : : success(data)"
OK-->>R : "IntoResponse"
R-->>C : "200 OK + JSON"
else "失败"
S-->>H : "返回错误"
H->>ERR : "构造 AppError 或返回错误"
ERR-->>R : "IntoResponse"
R-->>C : "500 Internal Server Error + JSON"
end
图表来源
详细组件分析
HttpResult 泛型结果类型
-
设计理念
- 统一响应格式:所有API响应均包含code、message、data、tid与success字段,便于前端统一解析与展示。
- 成功路径:success(data)构造,code默认“0000”,success=true。
- 失败路径:error(code, message)构造,success=false;internal_error(message)为内部错误的快捷方式。
- 上下文追踪:自动从OpenTelemetry上下文提取trace_id,若无则置空,便于日志与链路追踪。
- 序列化策略:自定义Serialize实现,显式写出5个字段,其中success根据code是否为“0000”动态计算。
- 响应适配:实现IntoResponse,优先返回JSON,序列化失败时降级为500与纯文本。
-
关键行为与复杂度
- 构造函数O(1),序列化O(n)(n为data序列化开销),IntoResponse序列化O(1)+序列化开销。
- trace_id提取依赖当前span上下文,若无效则返回None,不影响响应正确性。
-
使用建议
- 成功场景:优先使用success(data)返回结构化数据。
- 失败场景:明确错误码与message,避免使用internal_error除非无法确定具体原因。
- 数据为空:data字段可为None,但需保证业务语义清晰。
章节来源
AppError 错误体系
-
设计理念
- 统一错误抽象:通过枚举封装常见错误来源,便于集中处理与上报。
- 易于扩展:支持From实现,如tokio mpsc SendError的转换,便于在异步通道中传播错误。
- 标准化输出:IntoResponse固定返回500状态码与包含error.code与error.message的对象,便于前端统一处理。
-
错误分类与构造
- AnyhowError:包装底层异常,便于上抛。
- IoError:包装IO错误。
- Generic:通用错误,支持validation_error与internal_server_error等便捷方法。
-
使用建议
- 业务层尽量将错误转换为明确的错误码与message,必要时使用AppError::Generic承载。
- 对于可恢复的业务错误,优先返回HttpResult::error(...)而非抛出AppError,以便客户端区分业务错误与系统错误。
章节来源
Axum处理器中的返回类型使用
- 返回类型约定
- 成功:Result<HttpResult, AppError>,处理器返回Ok(HttpResult::success(...))或Ok(HttpResult::error(...))。
- 失败:Result<HttpResult, AppError>,处理器返回Err(AppError::...)或Ok(HttpResult::error(...))。
- 示例:rcoder与agent_runner的agent_status处理器均采用该模式,先做参数校验,再构造AgentStatusResponse并返回HttpResult.success(...),或在参数非法时返回HttpResult.error(...)。
flowchart TD
Start(["进入处理器"]) --> Validate["校验输入参数"]
Validate --> Valid{"参数有效?"}
Valid --> |否| BuildErr["构造 HttpResult::error(code, message)"]
BuildErr --> ReturnErr["返回 Ok(HttpResult::error)"]
Valid --> |是| DoBiz["执行业务逻辑"]
DoBiz --> BizOK{"业务成功?"}
BizOK --> |否| BuildBizErr["构造 HttpResult::error(code, message)"]
BuildBizErr --> ReturnBizErr["返回 Ok(HttpResult::error)"]
BizOK --> |是| BuildData["构造响应数据"]
BuildData --> ReturnOk["返回 Ok(HttpResult::success(data))"]
图表来源
章节来源
错误码与触发条件
- 内置错误码
- “0000”:成功。
- “5000”:内部错误(internal_error(message)构造)。
- 业务错误码示例
- “INVALID_PARAMS”:参数校验失败(例如agent_status处理器对project_id为空的处理)。
- “INVALID_SESSION”:会话无效(OpenAPI示例中出现)。
- “SESSION_NOT_FOUND”:会话不存在(OpenAPI示例中出现)。
- 触发条件
- 参数校验失败:处理器在进入业务逻辑前进行参数校验,不符合要求时返回HttpResult::error(...)。
- 业务状态异常:如Agent不存在、会话不存在等,返回相应错误码与message。
- 系统异常:无法预期的错误,使用AppError或HttpResult::internal_error(...)。
章节来源
错误上下文信息收集机制
- trace_id采集
- HttpResult在构造时与IntoResponse阶段均可从OpenTelemetry上下文提取trace_id,若当前span无效则置空。
- 该机制确保每个响应具备可追踪的链路标识,便于日志聚合与问题定位。
- 请求ID(request_id)
- 在聊天响应等结构中提供request_id字段,用于标识与追踪请求,便于跨服务关联。
- 会话消息中的错误字段
- 会话通知结构中包含错误信息字段,便于在SSE流中传递错误详情。
章节来源
序列化输出示例
- 成功响应(示例结构)
- 字段:code、message、data、tid、success
- data为对象或数组时,success为true;data为null时,success仍为true
- 失败响应(示例结构)
- 字段:code、message、data为null、tid、success为false
- 或AppError的标准化错误对象(error.code与error.message)
章节来源
客户端错误处理建议
- 成功与失败路径区分
- 优先依据success字段判断整体成功与否;若为false,读取error.code与error.message进行分支处理。
- 错误码映射
- 将“0000”视为成功;“5000”视为内部错误,提示用户稍后重试或上报工单。
- “INVALID_PARAMS”、“INVALID_SESSION”、“SESSION_NOT_FOUND”等业务错误码用于提示用户修正输入或重新发起请求。
- 上下文追踪
- 记录并回传tid,便于服务端定位问题;在客户端日志中附带request_id,便于跨服务关联。
- 降级与重试
- 对瞬时性错误(如网络抖动)建议客户端进行指数退避重试;对参数类错误直接提示用户修正。
依赖关系分析
- 组件耦合
- HttpResult与AppError均为共享类型,rcoder与agent_runner通过lib.rs统一导出使用,降低重复实现与耦合。
- 处理器依赖共享类型,路由层仅负责注册与文档生成,职责清晰。
- 外部依赖
- OpenTelemetry与tracing用于trace_id采集与日志追踪。
- serde、utoipa用于序列化与OpenAPI文档生成。
- axum用于HTTP响应适配与IntoResponse实现。
graph LR
HR["HttpResult<T>"] --> AX["axum::response::IntoResponse"]
HR --> OT["opentelemetry/tracing"]
HR --> SD["serde"]
AE["AppError"] --> AX
AE --> TH["thiserror"]
RC["rcoder/handler/*"] --> HR
RC --> AE
AR["agent_runner/handler/*"] --> HR
AR --> AE
图表来源
章节来源
性能考量
- 序列化成本
- HttpResult的序列化为结构体序列化,主要开销取决于data的大小;建议在成功路径仅返回必要字段,避免冗余数据。
- IntoResponse路径
- 成功路径返回200+JSON,失败路径返回500+JSON;序列化失败时降级为500+纯文本,避免中间件异常。
- trace_id采集
- trace_id提取依赖当前span上下文,若无上下文则跳过,不会引入额外开销。
故障排查指南
- 常见问题
- 响应未携带success字段:确认使用HttpResult而非自定义结构体。
- 错误响应格式不一致:统一使用AppError或HttpResult::error(...),避免混合返回。
- trace_id缺失:检查OpenTelemetry中间件是否正确注入span上下文。
- 定位步骤
- 根据tid在日志系统中检索对应链路。
- 结合request_id在聊天/会话相关接口中定位具体请求。
- 对业务错误码进行聚合统计,识别高频错误与潜在输入问题。
结论
通过HttpResult与AppError的组合,系统实现了统一、可观测、易维护的API响应模型。成功与失败路径清晰分离,错误码与上下文信息完整,配合Axum的IntoResponse实现,能够稳定地输出标准化响应。建议在所有新接口中遵循该模式,以提升客户端体验与运维效率。
附录
- 统一导出入口
- shared_types::lib.rs统一导出HttpResult与AppError,便于服务间复用。
- OpenAPI示例
- rcoder与agent_runner的OpenAPI文档中对HttpResult进行了标注与示例展示,便于客户端理解响应结构。
章节来源