This commit is contained in:
@@ -14,12 +14,15 @@ Gateway API 统一客户端,提供 14 个接口的类型安全封装。
|
||||
- `appSecret string` - 应用密钥
|
||||
- `httpClient *http.Client` - HTTP 客户端(支持连接复用)
|
||||
- `timeout time.Duration` - 请求超时时间
|
||||
- `logger *zap.Logger` - 日志记录器
|
||||
- `maxRetries int` - 最大重试次数
|
||||
|
||||
#### Scenario: 创建 Gateway 客户端
|
||||
|
||||
- **WHEN** 调用 `gateway.NewClient(baseURL, appID, appSecret)`
|
||||
- **WHEN** 调用 `gateway.NewClient(baseURL, appID, appSecret, logger)`
|
||||
- **THEN** 返回已初始化的 `Client` 实例
|
||||
- **AND** HTTP 客户端配置正确(支持 Keep-Alive)
|
||||
- **AND** 默认最大重试次数为 2
|
||||
|
||||
#### Scenario: 配置超时时间
|
||||
|
||||
@@ -29,15 +32,21 @@ Gateway API 统一客户端,提供 14 个接口的类型安全封装。
|
||||
|
||||
### Requirement: 统一请求方法
|
||||
|
||||
系统 SHALL 提供 `doRequest` 方法,统一处理加密、签名、HTTP 请求和响应解析。
|
||||
系统 SHALL 提供 `doRequest` 方法,统一处理加密、签名、HTTP 请求和响应解析。请求参数 SHALL 直接接收结构体,内部自动序列化并包装为 `{"params": <JSON>}` 格式。
|
||||
|
||||
#### Scenario: 请求参数自动序列化
|
||||
|
||||
- **WHEN** 调用 `doRequest(ctx, "/device/speed-limit", &SpeedLimitReq{CardNo: "xxx", SpeedLimit: 1024})`
|
||||
- **THEN** 请求结构体自动通过 `sonic.Marshal` 序列化
|
||||
- **AND** 序列化结果嵌入 `{"params": <序列化JSON>}` 中进行加密和签名
|
||||
|
||||
#### Scenario: 成功的 API 调用
|
||||
|
||||
- **WHEN** 调用 `doRequest(ctx, "/flow-card/status", businessData)`
|
||||
- **WHEN** 调用 `doRequest(ctx, "/flow-card/status", req)`
|
||||
- **THEN** 业务数据使用 AES-128-ECB 加密
|
||||
- **AND** 请求使用 MD5 签名
|
||||
- **AND** HTTP POST 发送到 `{baseURL}/flow-card/status`
|
||||
- **AND** 响应中的 `data` 字段解密并返回
|
||||
- **AND** 响应中的 `data` 字段返回为 `json.RawMessage`
|
||||
|
||||
#### Scenario: 网络错误
|
||||
|
||||
@@ -55,7 +64,7 @@ Gateway API 统一客户端,提供 14 个接口的类型安全封装。
|
||||
|
||||
- **WHEN** Gateway 响应无法解析为 JSON
|
||||
- **THEN** 返回 `CodeGatewayInvalidResp` 错误
|
||||
- **AND** 错误信息包含原始响应内容(限制 200 字符)
|
||||
- **AND** 错误信息包含原始响应内容
|
||||
|
||||
#### Scenario: Gateway 业务错误
|
||||
|
||||
@@ -63,6 +72,37 @@ Gateway API 统一客户端,提供 14 个接口的类型安全封装。
|
||||
- **THEN** 返回 `CodeGatewayError` 错误
|
||||
- **AND** 错误信息包含 Gateway 的 code 和 msg
|
||||
|
||||
### Requirement: 泛型响应解析方法
|
||||
|
||||
系统 SHALL 提供 `doRequestWithResponse[T any]` 泛型方法,自动完成请求发送和响应反序列化。
|
||||
|
||||
#### Scenario: 自动反序列化响应
|
||||
|
||||
- **WHEN** 调用 `doRequestWithResponse[CardStatusResp](ctx, "/flow-card/status", req)`
|
||||
- **THEN** 返回 `*CardStatusResp` 类型的结构体
|
||||
- **AND** 内部调用 `doRequest` 获取 `json.RawMessage` 后自动 unmarshal
|
||||
|
||||
#### Scenario: 反序列化失败
|
||||
|
||||
- **WHEN** Gateway 返回的 JSON 无法匹配目标结构体
|
||||
- **THEN** 返回 `CodeGatewayInvalidResp` 错误
|
||||
- **AND** 错误信息为 "解析 Gateway 响应失败"
|
||||
|
||||
### Requirement: 请求结构体直接序列化
|
||||
|
||||
系统 SHALL 消除手动 `map[string]interface{}` 构建,所有业务方法直接将请求结构体传递给 `doRequest` 或 `doRequestWithResponse`。
|
||||
|
||||
#### Scenario: 设备限速请求
|
||||
|
||||
- **WHEN** 调用 `SetSpeedLimit(ctx, &SpeedLimitReq{CardNo: "xxx", SpeedLimit: 1024})`
|
||||
- **THEN** `SpeedLimitReq` 结构体直接序列化为 JSON
|
||||
- **AND** 不再手动构建 `map[string]interface{}`
|
||||
|
||||
#### Scenario: 流量卡停机请求
|
||||
|
||||
- **WHEN** 调用 `StopCard(ctx, &CardOperationReq{CardNo: "xxx", Extend: "ext"})`
|
||||
- **THEN** `CardOperationReq` 结构体直接序列化
|
||||
- **AND** `Extend` 字段通过 `json:"extend,omitempty"` 标签在为空时自动省略
|
||||
### Requirement: 流量卡 API 封装
|
||||
|
||||
系统 SHALL 提供 7 个流量卡相关的 API 方法。
|
||||
|
||||
Reference in New Issue
Block a user