# 截图存储 Bug 修复说明 ## 问题描述 在实施 Base64 截图存储方案后,发现了一个严重的 Bug: ``` 错误信息: GET data:image/jpeg;base64:1 net::ERR_INVALID_URL ``` ## 根本原因 ### 问题分析 1. **数据存储方式**:使用逗号分隔的字符串存储多个截图 ```go screenshots := strings.Join(customer.Screenshots, ",") ``` 2. **数据读取方式**:使用逗号分割字符串 ```go c.Screenshots = strings.Split(screenshots.String, ",") ``` 3. **Base64 数据特点**:Base64 编码的字符串**本身不包含逗号**,但是... 4. **Data URL 格式**:`data:image/jpeg;base64,{base64_string}` - 注意:**逗号**是 Data URL 格式的一部分! - 格式:`data:{MIME类型};base64,{Base64数据}` ### 问题示例 假设有两张截图: **原始数据**: ```json [ "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "data:image/png;base64,iVBORw0KGgoAAAA..." ] ``` **存储到数据库**(使用逗号连接): ``` data:image/jpeg;base64,/9j/4AAQSkZJRg...,data:image/png;base64,iVBORw0KGgoAAAA... ``` **从数据库读取**(使用逗号分割): ```json [ "data:image/jpeg;base64", // ❌ 被截断! "/9j/4AAQSkZJRg...", // ❌ 不是有效的 Data URL "data:image/png;base64", // ❌ 被截断! "iVBORw0KGgoAAAA..." // ❌ 不是有效的 Data URL ] ``` **结果**:前端尝试加载 `data:image/jpeg;base64` 导致 `ERR_INVALID_URL` 错误! ## 解决方案 ### 修改存储格式 从**逗号分隔字符串**改为 **JSON 数组**: #### 修改前(错误) ```go // 存储 screenshots := strings.Join(customer.Screenshots, ",") // 读取 c.Screenshots = strings.Split(screenshots.String, ",") ``` #### 修改后(正确) ```go // 存储 screenshotsJSON, err := json.Marshal(customer.Screenshots) // 结果: ["data:image/jpeg;base64,...","data:image/png;base64,..."] // 读取 var screenshotArray []string json.Unmarshal([]byte(screenshots.String), &screenshotArray) ``` ### 向后兼容 为了兼容旧数据(文件路径格式),添加了降级处理: ```go if screenshots.Valid && screenshots.String != "" { // 尝试解析为 JSON 数组 var screenshotArray []string if err := json.Unmarshal([]byte(screenshots.String), &screenshotArray); err == nil { c.Screenshots = screenshotArray } else { // 向后兼容:如果不是 JSON,尝试逗号分隔(旧格式) c.Screenshots = strings.Split(screenshots.String, ",") } } else { c.Screenshots = []string{} } ``` ## 修改文件清单 ### `/internal/storage/mysql_customer_storage.go` 1. **添加导入** ```go import "encoding/json" ``` 2. **修改 `GetAllCustomers` 方法** - 使用 `json.Unmarshal` 解析 screenshots 字段 - 添加向后兼容逻辑 3. **修改 `GetCustomerByID` 方法** - 使用 `json.Unmarshal` 解析 screenshots 字段 - 添加向后兼容逻辑 4. **修改 `CreateCustomer` 方法** - 使用 `json.Marshal` 序列化 screenshots 数组 5. **修改 `UpdateCustomer` 方法** - 使用 `json.Marshal` 序列化 screenshots 数组 ## 数据格式对比 ### 旧格式(文件路径 - 使用逗号分隔) ``` 数据库存储: /static/uploads/1.jpg,/static/uploads/2.png 解析结果: ["/static/uploads/1.jpg", "/static/uploads/2.png"] 状态: ✅ 正常(路径中没有逗号) ``` ### 错误格式(Base64 - 使用逗号分隔) ``` 数据库存储: data:image/jpeg;base64,abc...,data:image/png;base64,xyz... 解析结果: ["data:image/jpeg;base64", "abc...", "data:image/png;base64", "xyz..."] 状态: ❌ 错误(Data URL 被逗号截断) ``` ### 新格式(JSON 数组) ``` 数据库存储: ["data:image/jpeg;base64,abc...","data:image/png;base64,xyz..."] 解析结果: ["data:image/jpeg;base64,abc...", "data:image/png;base64,xyz..."] 状态: ✅ 正常(完整的 Data URL) ``` ## 测试验证 ### 1. 单元测试数据 ```go // 测试 JSON 序列化 screenshots := []string{ "data:image/jpeg;base64,/9j/4AAQSkZJRg...", "data:image/png;base64,iVBORw0KGgoAAAA...", } json, _ := json.Marshal(screenshots) fmt.Println(string(json)) // 输出: ["data:image/jpeg;base64,/9j/4AAQSkZJRg...","data:image/png;base64,iVBORw0KGgoAAAA..."] // 测试 JSON 反序列化 var result []string json.Unmarshal(json, &result) fmt.Println(result) // 输出: [data:image/jpeg;base64,/9j/4AAQSkZJRg... data:image/png;base64,iVBORw0KGgoAAAA...] ``` ### 2. 集成测试 ```bash # 1. 上传截图 curl -X POST http://localhost:8081/api/upload \ -F "screenshots=@test.jpg" # 2. 创建客户 curl -X POST http://localhost:8081/api/customers \ -H "Content-Type: application/json" \ -d '{ "customerName": "测试", "screenshots": ["data:image/jpeg;base64,/9j/4AAQ..."] }' # 3. 查询客户 curl http://localhost:8081/api/customers/{id} # 4. 验证数据库 mysql> SELECT screenshots FROM customers WHERE id = '{id}'; # 应该看到: ["data:image/jpeg;base64,/9j/4AAQ..."] ``` ## 经验教训 ### 1. 分隔符选择的重要性 当使用分隔符连接字符串时,必须确保: - ✅ 分隔符不会出现在数据中 - ✅ 或者使用转义机制 - ✅ 或者使用结构化格式(如 JSON) ### 2. Data URL 格式 ``` data:[][;base64], ^ ^ ^ | | | MIME类型 编码 逗号分隔符(重要!) ``` 逗号是 Data URL 规范的一部分,不能用作数组分隔符! ### 3. 最佳实践 对于复杂数据结构,优先使用: 1. **JSON** - 结构化、标准、易于解析 2. **Protocol Buffers** - 高性能、类型安全 3. **避免自定义分隔符** - 容易出错 ### 4. 向后兼容 在修改数据格式时,务必考虑: - 现有数据的迁移 - 降级处理逻辑 - 渐进式升级策略 ## 总结 这个 Bug 的根本原因是:**使用逗号分隔包含逗号的数据**。 修复方案:**使用 JSON 数组格式存储和解析数据**。 这是一个典型的**数据格式设计问题**,提醒我们在设计数据存储格式时,必须充分考虑数据的特性和边界情况。