1
0
Files
nex/openspec/specs/request-validation/spec.md
lanyuanxiaoyao d92db73937 refactor: 后端代码质量优化 - 复用公共库、使用标准库、类型安全错误判断
## 高优先级修复
- stats_service_impl: 使用 strings.SplitN 替代错误的索引分割
- provider_handler: 使用 errors.Is(err, gorm.ErrDuplicatedKey) 替代字符串匹配
- client: 重写 isNetworkError 使用 errors.As/Is 类型安全判断
- proxy_handler: 使用 encoding/json 标准库解析 JSON(extractModelName、isStreamRequest)

## 中优先级修复
- stats_handler: 添加 parseDateParam 辅助函数消除重复日期解析
- pkg/errors: 新增 ErrRequestCreate/Send/ResponseRead 错误类型和 WithCause 方法
- client: 使用结构化错误替代 fmt.Errorf
- ConversionEngine: logger 依赖注入,替换所有 zap.L() 调用

## 低优先级修复
- encoder: 删除 joinStrings,使用 strings.Join
- adapter: 删除 modelInfoRegex 正则,使用 isModelInfoPath 字符串函数

## 文档更新
- README.md: 添加公共库使用指南和编码规范章节
- specs: 同步 delta specs 到 main specs(error-handling、structured-logging、request-validation)

## 归档
- openspec/changes/archive/2026-04-20-refactor-backend-code-quality/
2026-04-20 16:42:48 +08:00

149 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Request Validation
## ADDED Requirements
### Requirement: 使用 validator 库
系统 SHALL 使用 go-playground/validator 进行请求验证。
#### Scenario: 验证器初始化
- **WHEN** 应用启动
- **THEN** SHALL 初始化 validator 实例
- **THEN** SHALL 注册自定义验证规则
#### Scenario: 验证规则定义
- **WHEN** 定义请求结构体
- **THEN** SHALL 使用 struct tag 定义验证规则
- **THEN** SHALL 支持必需字段、范围、格式等验证
### Requirement: 验证 OpenAI 请求
系统 SHALL 验证 OpenAI ChatCompletionRequest验证逻辑位于 ProtocolAdapter 的 decodeRequest 内。
#### Scenario: 必需字段验证
- **WHEN** OpenAI Adapter 的 decodeRequest 解析请求
- **THEN** SHALL 验证 model 字段不为空
- **THEN** SHALL 验证 messages 字段不为空且至少有一条消息
- **THEN** 验证失败 SHALL 返回 INVALID_INPUT 类型的 ConversionError
#### Scenario: 参数范围验证
- **WHEN** OpenAI Adapter 的 decodeRequest 解析参数
- **THEN** SHALL 验证 temperature 范围在 [0, 2]
- **THEN** SHALL 验证 max_tokens 大于 0
- **THEN** SHALL 验证 top_p 范围在 (0, 1]
#### Scenario: 消息内容验证
- **WHEN** 验证 messages 字段
- **THEN** SHALL 验证每条消息的 role 有效system、developer、user、assistant、tool
- **THEN** SHALL 验证 content 不为空
### Requirement: 验证 Anthropic 请求
系统 SHALL 验证 Anthropic MessagesRequest验证逻辑位于 ProtocolAdapter 的 decodeRequest 内。
#### Scenario: 必需字段验证
- **WHEN** Anthropic Adapter 的 decodeRequest 解析请求
- **THEN** SHALL 验证 model 字段不为空
- **THEN** SHALL 验证 messages 字段不为空且至少有一条消息
- **THEN** SHALL 验证 max_tokens 大于 0或使用默认值
#### Scenario: 参数范围验证
- **WHEN** Anthropic Adapter 的 decodeRequest 解析参数
- **THEN** SHALL 验证 temperature 范围在 [0, 1]
- **THEN** SHALL 验证 top_p 范围在 (0, 1]
#### Scenario: 消息内容验证
- **WHEN** 验证 messages 字段
- **THEN** SHALL 验证每条消息的 role 有效user、assistant
- **THEN** SHALL 验证 content 数组不为空
### Requirement: 验证管理 API 请求
系统 SHALL 验证管理 API 请求。
#### Scenario: Provider 创建验证
- **WHEN** 创建 Provider
- **THEN** SHALL 验证 id、name、api_key、base_url 字段不为空
- **THEN** SHALL 验证 base_url 格式有效URL 格式)
- **THEN** SHALL 验证 id 格式(字母、数字、下划线、连字符)
#### Scenario: Model 创建验证
- **WHEN** 创建 Model
- **THEN** SHALL 验证 id、provider_id、model_name 字段不为空
- **THEN** SHALL 验证 provider_id 存在
#### Scenario: 更新请求验证
- **WHEN** 更新资源
- **THEN** SHALL 验证至少提供一个可更新字段
- **THEN** SHALL 验证字段值有效性
### Requirement: 返回友好的验证错误
系统 SHALL 返回友好的验证错误响应。
#### Scenario: 转换错误格式
- **WHEN** decodeRequest 验证失败返回 ConversionError
- **THEN** ProxyHandler SHALL 使用 clientAdapter.encodeError 编码错误响应
- **THEN** 错误 SHALL 使用客户端协议的格式
#### Scenario: 多字段错误
- **WHEN** 多个字段验证失败
- **THEN** ConversionError.details SHALL 包含所有验证错误
- **THEN** 错误响应 SHALL 包含完整的验证错误信息
### Requirement: 在 handler 中应用验证
系统 SHALL 在 handler 中应用验证。
#### Scenario: 验证中间件
- **WHEN** 使用验证中间件
- **THEN** SHALL 在请求解析后立即验证
- **THEN** SHALL 在验证失败时提前返回错误
- **THEN** SHALL 避免执行后续处理逻辑
#### Scenario: 验证时机
- **WHEN** 处理请求
- **THEN** SHALL 在 handler 函数开始时验证
- **THEN** SHALL 在验证通过后才执行业务逻辑
### Requirement: 使用标准库解析 JSON
系统 SHALL 使用 encoding/json 标准库解析 JSON 请求。
#### Scenario: 提取 model 字段
- **WHEN** 从请求体提取 model 字段
- **THEN** SHALL 使用 json.Unmarshal 解析到结构体
- **THEN** SHALL NOT 手动扫描字节查找字段
- **THEN** 解析失败 SHALL 返回空字符串(不报错)
#### Scenario: 检测 stream 字段
- **WHEN** 检测请求是否为流式请求
- **THEN** SHALL 使用 json.Unmarshal 解析到结构体
- **THEN** SHALL NOT 手动扫描字节查找字段
- **THEN** 解析失败 SHALL 返回 false非流式
#### Scenario: JSON 解析健壮性
- **WHEN** 解析 JSON 请求体
- **THEN** SHALL 正确处理转义字符
- **THEN** SHALL 正确处理嵌套结构
- **THEN** SHALL 正确处理 Unicode 字符
- **THEN** 解析失败 SHALL 有明确的错误处理