Page:
T-244
Pages
00-ai-start-here
01-vision
02-requirements
03-tech-stack
04-architecture
05-coding-rules
06-tasks
07-user-stories
08-interaction-checklist
Design
Home
Integrations-shunyunbao-contract
PPT
T-001
T-002
T-003
T-004
T-101
T-102
T-103
T-104
T-201
T-202
T-203
T-204
T-205
T-206
T-207
T-208
T-209
T-210
T-211
T-212
T-213
T-214
T-215
T-216
T-217
T-218
T-219
T-220
T-221
T-222
T-223
T-224
T-225
T-226
T-227
T-228
T-229
T-230
T-231
T-232
T-233
T-234
T-235
T-236
T-237
T-238
T-239
T-240
T-241
T-242
T-243
T-244
T-245
T-246
T-247
T-248
T-249
T-250
T-251
T-252
T-253
T-254
T-255
T-256
T-257
T-258
T-259
T-260
T-261
T-262
T-263
T-264
T-265
T-266
T-267
T-268
T-269
T-270
T-271
T-272
T-273
T-274
T-275
T-276
T-277
T-278
T-279
T-280
T-281
Task-Template
Tasks
agent-context
api
clean-state-checklist
current-state
routes
Clone
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.
同步来源:
docs/tasks/T-244.md· commitafc651f75a3a
id: T-244 title: 兼容 ERP 图片响应缺少媒体类型 phase: 2 deps:
- T-241
status: DONE
created: 2026-07-29
context_ref:
24eef29work_branch: null write_paths: - docs/tasks/T-244.md
- docs/current-state.md
- backend-api/internal/platform/shunyunbao/image.go
- backend-api/internal/platform/shunyunbao/image_test.go
Bug / 背景
完整单号同步成功后,商品图片可能显示“图片获取失败”。只读数据审计确认图片引用为规范正
整数,图片记录为 FAILED / ERP_IMAGE_INVALID,不是货运导入失败。
真实 /api/p/file?id=<numeric-id> 响应为 HTTP 200,正文是有效且很小的 JPEG,但 ERP
未返回 Content-Type、Content-Length,只通过 Content-Disposition 提供 .jpg
文件名。当前 Go 客户端无条件执行 mime.ParseMediaType(Content-Type),空响应头在正文
进入本地图片存储前就被归类为无效图片。
图片缓存是货运同步后的 best-effort 阶段,所以该错误不会回滚已成功保存的货运头和商品; 页面只显示统一失败标签,实际稳定错误码保存在图片状态记录中。
修订契约
- HTTP 2xx 且
Content-Type为image/jpeg、image/png、image/webp时沿用现有路径。 Content-Type缺失或规范化后为application/octet-stream时,只读取正文前最多 512 字节;JPEG/PNG 使用 Go 标准库http.DetectContentType,WebP 使用严格RIFF....WEBP文件签名判定。- 嗅探只接受 JPEG、PNG、WebP;空正文、JSON、HTML、SVG、未知二进制继续返回
ErrFreightImageInvalid。 - 已读取的前缀必须无损拼回返回流,后续本地存储继续执行完整解码、声明类型一致性、 尺寸/像素、20 MB、归一化 JPEG 和 SHA-256 校验。
- ERP 明确声明其他媒体类型时 fail-closed,不用文件扩展名覆盖响应头。
- 不信任或解析
Content-Disposition文件名,不扩大 URL、重定向或 ERP 会话边界。
方案
- 在顺运宝图片适配器中增加小型媒体类型解析函数:先规范化响应头,支持类型直接返回; 仅对缺失/通用二进制响应调用内容嗅探。
- 使用固定 512 字节
bufio.Reader执行Peek;短图片允许io.EOF,空正文拒绝。成功 时返回组合了 buffered reader 和原响应 body closer 的流,避免丢失或复制完整图片。 - 继续在读取正文前拒绝已知超出 20 MB 的
Content-Length;未知长度由现有 asset store 的LimitReader(MaxInputBytes+1)强制限制。 - 测试覆盖缺失媒体类型的 JPEG、通用二进制 PNG/WebP、短正文、明确 JSON、嗅探非图片、 声明图片类型、超大已知长度和前缀不丢失。
- 修复部署后重新以相同完整订单号同步即可重试
status != READY的图片;本任务不增加 独立重试按钮或后台定时重试。
验收要点
- 缺少
Content-Type的有效 JPEG 保存为本系统归一化 JPEG,图片状态为READY。 application/octet-stream的有效 PNG/WebP 可以进入既有解码与存储路径。- 嗅探不会丢失正文前缀,完整内容只读取一次并最终关闭 ERP 响应 body。
- JSON、HTML、SVG、空正文、未知二进制和明确不支持的媒体类型仍被拒绝。
- 已知或流式超限图片仍受 20 MB 限制,不能绕过 asset store。
- 401/403、404、非 2xx、会话清理、固定 URL 和数字 ID 校验不回归。
- 货运同步仍为图片 best-effort,不因单张图片失败回滚业务数据。
- 标准 Go 测试、race、vet 和三个入口构建通过。
边界
- 不修改顺运宝 ERP,不上传或回写 ERP 图片。
- 不直接在 Admin 页面引用 ERP URL;图片仍保存到
CMROUBAO_ASSET_DIR并从鉴权路由读取。 - 不接受 SVG、GIF、BMP、ICO、PDF 或任意未知格式。
- 不以扩展名、文件名或
Content-Disposition替代正文验证。 - 不记录图片正文、Cookie、Token、真实订单、商品、店铺或图片 ID。
执行记录
- 2026-07-29:真实只读审计确认货运同步成功,单张图片失败码为
ERP_IMAGE_INVALID;受控响应探测确认 HTTP 200 正文为有效 JPEG,但Content-Type和Content-Length均缺失。根因位于 source adapter 的响应头强校验, 不是 ERP 鉴权、数字图片 ID、图片不存在、本地目录或图片体积。 - 2026-07-29:适配器仅对缺失媒体类型或
application/octet-stream响应使用固定 512 字节 buffered peek;支持头直接沿用,明确 JSON/HTML/SVG 等类型保持 fail-closed。 成功流组合 buffered reader 与原 body closer,既不丢前缀,也不复制完整图片。 - 2026-07-29:测试确认 Go 1.23 的
http.DetectContentType不识别 WebP,因此增加 严格RIFF....WEBP前缀检测;asset store 随后仍执行完整 WebP 解码、媒体类型一致性、 尺寸/像素与 20 MB 校验。端到端测试已将缺失响应头的有效 JPEG 归一化保存并重新解码。 - 2026-07-29:
go test ./...、go test -race ./...、go vet ./...和 API、 authctl、migrate 三个入口构建通过。测试覆盖缺失/通用媒体类型、JPEG/PNG/WebP、 前缀完整性、body 关闭语义、明确非图片、嗅探非图片、已知超限、401/403、404 与非 2xx; 自动化验证未访问真实 ERP。