# 参数校验 Bug 报告 ## BUG-001 **严重程度**:高 **问题描述**: `POST /api/v1/partners` 接口缺少对 `name` 字段的必填校验。传入空 `name` 时,handler 成功通过 `ShouldBindJSON` 绑定并返回 201,而不是期望的 400。 **复现步骤**: 1. 调用 `POST /api/v1/partners`,body 为 `{"type":"supplier"}`(不含 name) 2. 期望返回 400,实际返回 201 **失败的测试用例**: ```go func TestPartnerHandler_Create_MissingName(t *testing.T) { // 这个测试会失败,揭示了 partner handler 缺少 name 必填校验 body := `{"type":"supplier"}` w := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/api/v1/partners", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") // 预期 400,实际得到 201 } ``` **根因分析**: `backend/internal/model/partner.go` 第 6 行: ```go Name string `gorm:"size:200;not null" json:"name"` ``` 结构体 `Name` 字段只有 GORM 的 `not null` 约束,没有 `binding:"required"` 标签。 `c.ShouldBindJSON` 只校验 `binding` 标签,不校验 GORM 标签,导致空 name 可以通过校验。 SQLite in-memory 不严格强制 NOT NULL 约束(与 MySQL 行为不同),所以数据库层面也未报错。 **修复建议**: 在 `Partner` model 的 `Name` 字段添加 `binding:"required"` 标签: ```go Name string `gorm:"size:200;not null" json:"name" binding:"required"` ``` 或者在 handler 中手动校验: ```go if req.Name == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"}) return } ``` --- ## BUG-002 **严重程度**:高 **问题描述**: `POST /api/v1/stock-in/orders` 接口缺少对 `warehouse_id` 字段的必填校验。传入 `warehouse_id: 0`(JSON 中省略该字段时默认为 0)时,handler 返回 201,而不是期望的 400。 **复现步骤**: 1. 调用 `POST /api/v1/stock-in/orders`,body 为 `{"items":[]}`(不含 warehouse_id) 2. 期望返回 400,实际返回 201 **失败的测试用例**: ```go func TestStockInHandler_Create_MissingWarehouse(t *testing.T) { body := `{"items":[]}` // 预期 400,实际得到 201 } ``` **根因分析**: `backend/internal/model/stock.go` 第 10 行: ```go WarehouseID uint64 `gorm:"not null" json:"warehouse_id"` ``` 同 BUG-001,结构体只有 GORM 约束,缺少 `binding:"required"`。 对于 `uint64` 类型,JSON 省略时默认值为 0,`ShouldBindJSON` 不会报错。 **修复建议**: 在 `StockInOrder.WarehouseID` 添加 `binding:"required,min=1"` 标签: ```go WarehouseID uint64 `gorm:"not null" json:"warehouse_id" binding:"required,min=1"` ``` 或在 handler `Create` 函数中(`backend/internal/handler/stock_in.go`,约第 82 行)手动校验: ```go if req.WarehouseID == 0 { c.JSON(http.StatusBadRequest, gin.H{"error": "warehouse_id is required"}) return } ``` --- ## BUG-003 **严重程度**:高 **问题描述**: `POST /api/v1/stock-out/orders` 接口缺少对 `warehouse_id` 字段的必填校验,与 BUG-002 问题相同。 **复现步骤**: 1. 调用 `POST /api/v1/stock-out/orders`,body 为 `{"items":[]}`(不含 warehouse_id) 2. 期望返回 400,实际返回 201 **失败的测试用例**: ```go func TestStockOutHandler_Create_MissingWarehouse(t *testing.T) { body := `{"items":[]}` // 预期 400,实际得到 201 } ``` **根因分析**: 同 BUG-002,`backend/internal/model/stock.go` 的 `StockOutOrder.WarehouseID` 缺少 `binding` 校验标签。 **修复建议**: 在 `StockOutOrder.WarehouseID` 添加 `binding:"required,min=1"` 标签,或在 `backend/internal/handler/stock_out.go` 的 `Create` 函数中手动校验。