修复公网 HTTP 下蝦皮规格 AI 匹配无法保存 #182

Open
opened 2026-09-01 00:42:52 +08:00 by ila · 2 comments
Owner

原始需求摘要

2026-09-01 用户反馈:线上蝦皮商品详情页面 AI 匹配颜色尺码后不能保存;要求分析原因、修复、打包部署,并在浏览器回归。

当前事实与根因

  • 线上管理端地址为公网 HTTP,浏览器返回 window.isSecureContext=false。
  • 该环境中 window.crypto.randomUUID 不存在。
  • 蝦皮规格批量保存会在每次 PUT 前直接调用 crypto.randomUUID();因此点击“保存修改”后在首个请求前抛出前端异常,服务端没有收到保存请求。
  • 同类调用散布于多个 Admin 写操作,公网 HTTP 下均存在相同失败风险。
  • Gitea MCP 当前不可用,本工单按仓库规则回退 Gitea API 创建;凭据仅从本机 gitea.env 读取且不写入工单或日志。

目标

提供一个兼容 HTTP/HTTPS 的前端 requestId 生成函数,统一替换 Admin 页面直接调用 crypto.randomUUID() 的写操作;恢复蝦皮 AI 颜色/尺码建议保存,并避免同类公网 HTTP 写操作继续失效。

非目标

  • 不修改 AI 匹配策略、映射状态机、权限或服务端接口。
  • 不修改采购安全边界、价格保护或 Android Agent。
  • 不将管理端 HTTP 改造为推荐部署方式;HTTPS 仍是默认安全方案。

方案

  1. 新增前端 requestId 工具:优先使用 crypto.randomUUID();不可用时使用 crypto.getRandomValues() 生成 RFC 4122 v4 UUID;若 Web Crypto 整体不可用则明确报错,不使用低熵伪随机数。
  2. 将 web/src 中直接生成 requestId 的调用统一迁移到该工具。
  3. 增加工具单元测试,覆盖原生 randomUUID 与 HTTP 兼容回退路径。
  4. 运行 Web lint、单元测试、生产构建;提交推送后部署线上。
  5. 在公网 HTTP 线上页面重新执行 AI 匹配并保存,核对成功提示、保存后状态及服务端请求。

验收标准

  • 公网 HTTP 管理端中,蝦皮商品 AI 匹配草稿可成功保存。
  • 保存后详情刷新,映射进入既有“AI 待确认”状态,保存按钮不再保留未保存变更。
  • 页面不依赖 HTTP 环境中缺失的 crypto.randomUUID()。
  • 现有 HTTPS/安全上下文继续使用浏览器原生 UUID。
  • Web lint、单元测试和生产构建通过。
  • 最新提交已推送并部署到 185.216.248.75,浏览器回归通过。

风险与发布

  • 发布会更新线上 Web 静态资源并重启既有服务;用户已在原始请求中明确要求部署。
  • 浏览器回归会把商品 ID 17900 的 AI 建议保存为待确认映射,不会创建采购任务、订单或付款。

文档影响

无长期文档影响:仅恢复现有 requestId 契约在已允许的 HTTP 管理端环境中的实现兼容性,不改变 API、数据结构、业务规则、安全边界或运维命令,因此跳过 Wiki 更新与同步。

## 原始需求摘要 2026-09-01 用户反馈:线上蝦皮商品详情页面 AI 匹配颜色尺码后不能保存;要求分析原因、修复、打包部署,并在浏览器回归。 ## 当前事实与根因 - 线上管理端地址为公网 HTTP,浏览器返回 `window.isSecureContext=false`。 - 该环境中 `window.crypto.randomUUID` 不存在。 - 蝦皮规格批量保存会在每次 PUT 前直接调用 `crypto.randomUUID()`;因此点击“保存修改”后在首个请求前抛出前端异常,服务端没有收到保存请求。 - 同类调用散布于多个 Admin 写操作,公网 HTTP 下均存在相同失败风险。 - Gitea MCP 当前不可用,本工单按仓库规则回退 Gitea API 创建;凭据仅从本机 `gitea.env` 读取且不写入工单或日志。 ## 目标 提供一个兼容 HTTP/HTTPS 的前端 requestId 生成函数,统一替换 Admin 页面直接调用 `crypto.randomUUID()` 的写操作;恢复蝦皮 AI 颜色/尺码建议保存,并避免同类公网 HTTP 写操作继续失效。 ## 非目标 - 不修改 AI 匹配策略、映射状态机、权限或服务端接口。 - 不修改采购安全边界、价格保护或 Android Agent。 - 不将管理端 HTTP 改造为推荐部署方式;HTTPS 仍是默认安全方案。 ## 方案 1. 新增前端 requestId 工具:优先使用 `crypto.randomUUID()`;不可用时使用 `crypto.getRandomValues()` 生成 RFC 4122 v4 UUID;若 Web Crypto 整体不可用则明确报错,不使用低熵伪随机数。 2. 将 `web/src` 中直接生成 requestId 的调用统一迁移到该工具。 3. 增加工具单元测试,覆盖原生 randomUUID 与 HTTP 兼容回退路径。 4. 运行 Web lint、单元测试、生产构建;提交推送后部署线上。 5. 在公网 HTTP 线上页面重新执行 AI 匹配并保存,核对成功提示、保存后状态及服务端请求。 ## 验收标准 - 公网 HTTP 管理端中,蝦皮商品 AI 匹配草稿可成功保存。 - 保存后详情刷新,映射进入既有“AI 待确认”状态,保存按钮不再保留未保存变更。 - 页面不依赖 HTTP 环境中缺失的 `crypto.randomUUID()`。 - 现有 HTTPS/安全上下文继续使用浏览器原生 UUID。 - Web lint、单元测试和生产构建通过。 - 最新提交已推送并部署到 185.216.248.75,浏览器回归通过。 ## 风险与发布 - 发布会更新线上 Web 静态资源并重启既有服务;用户已在原始请求中明确要求部署。 - 浏览器回归会把商品 ID 17900 的 AI 建议保存为待确认映射,不会创建采购任务、订单或付款。 ## 文档影响 无长期文档影响:仅恢复现有 requestId 契约在已允许的 HTTP 管理端环境中的实现兼容性,不改变 API、数据结构、业务规则、安全边界或运维命令,因此跳过 Wiki 更新与同步。
Author
Owner

补充实测:当前公网 HTTP Chrome 中不仅 crypto.randomUUID 缺失,crypto.getRandomValues 也不可用。因此兼容层按“原生 randomUUID → getRandomValues → 非安全用途的本地 UUID v4 伪随机字节”降级。requestId 仅用于幂等去重,不作为密码、令牌或安全随机数;该回退才能覆盖本次真实线上环境。

补充实测:当前公网 HTTP Chrome 中不仅 `crypto.randomUUID` 缺失,`crypto.getRandomValues` 也不可用。因此兼容层按“原生 randomUUID → getRandomValues → 非安全用途的本地 UUID v4 伪随机字节”降级。requestId 仅用于幂等去重,不作为密码、令牌或安全随机数;该回退才能覆盖本次真实线上环境。
Author
Owner

实施完成,待用户验收

根因

线上管理端运行于公网 HTTP,浏览器实测 window.isSecureContext=false,且 crypto.randomUUID / crypto.getRandomValues 均不可用。蝦皮规格保存函数在发出首个 PUT 前直接调用 crypto.randomUUID(),因此点击保存时前端同步中断,服务端没有任何保存请求;AI 建议接口本身不生成 requestId,所以能正常返回。

实现

  • 新增统一 createRequestId():原生 randomUUID → getRandomValues → 仅用于幂等键的本地 UUID v4 回退。
  • 将 Admin GoAuto 页面中所有直接调用 crypto.randomUUID() 的写操作迁移到统一工具,避免同一 HTTP 环境下其他保存/创建动作发生相同故障。
  • 新增 3 个单元测试,覆盖原生、Web Crypto 随机字节和无 Web Crypto 的公网 HTTP 场景。
  • 不改变接口、数据结构、映射状态机、权限和采购安全边界。

提交:dce4a4f fix(web): support request IDs over HTTP (#182),已推送 origin/main。

自动化验证

  • pnpm exec jest tests/unit/utils/request-id.spec.js --runInBand:3/3 通过。
  • pnpm test:unit -- --runInBand:10 suites、36 tests 全部通过。
  • 本次变更文件定向 ESLint:通过。
  • pnpm build:prod:通过。
  • 全量 pnpm lint 仍被 web/src/views/goauto/purchase-tasks/index.vue 的既有混合 Tab/空格阻断;对 git show HEAD^ 的基线文件单独运行 ESLint,同样有 24 个错误,确认不是本工单引入。本工单未混入无关格式化。

部署

  • 发布目录:/home/goauto/releases/20260901-005500-dce4a4f
  • /home/goauto/current 已切换到该目录。
  • goauto.service:active。
  • 127.0.0.1:8010 与 127.0.0.1:9527 健康检查通过。
  • 发布前确认运行中采集任务 0、执行/提交中的采购任务 0。

线上浏览器回归

在 http://185.216.248.75:9527/#/shopee-products/index?productId=17900:

  1. 重新执行颜色 AI 匹配,生成 5/6 条建议。
  2. 点击“保存修改”成功;服务端日志记录连续 5 次 PUT /api/admin/v1/shopee-products/17900/specs/mapping。
  3. 详情刷新后显示 5/6 已匹配、5 条“AI 待确认”;“保存修改”变为禁用,说明没有未保存草稿。
  4. 浏览器 error/warn 日志为空。

回归只保存既有 AI 建议为待确认映射,未确认映射、未创建采购任务、订单或付款。

文档影响

无长期事实变化,按工单方案跳过 Wiki 更新与同步。

## 实施完成,待用户验收 ### 根因 线上管理端运行于公网 HTTP,浏览器实测 `window.isSecureContext=false`,且 `crypto.randomUUID` / `crypto.getRandomValues` 均不可用。蝦皮规格保存函数在发出首个 PUT 前直接调用 `crypto.randomUUID()`,因此点击保存时前端同步中断,服务端没有任何保存请求;AI 建议接口本身不生成 requestId,所以能正常返回。 ### 实现 - 新增统一 `createRequestId()`:原生 `randomUUID` → `getRandomValues` → 仅用于幂等键的本地 UUID v4 回退。 - 将 Admin GoAuto 页面中所有直接调用 `crypto.randomUUID()` 的写操作迁移到统一工具,避免同一 HTTP 环境下其他保存/创建动作发生相同故障。 - 新增 3 个单元测试,覆盖原生、Web Crypto 随机字节和无 Web Crypto 的公网 HTTP 场景。 - 不改变接口、数据结构、映射状态机、权限和采购安全边界。 提交:`dce4a4f fix(web): support request IDs over HTTP (#182)`,已推送 `origin/main`。 ### 自动化验证 - `pnpm exec jest tests/unit/utils/request-id.spec.js --runInBand`:3/3 通过。 - `pnpm test:unit -- --runInBand`:10 suites、36 tests 全部通过。 - 本次变更文件定向 ESLint:通过。 - `pnpm build:prod`:通过。 - 全量 `pnpm lint` 仍被 `web/src/views/goauto/purchase-tasks/index.vue` 的既有混合 Tab/空格阻断;对 `git show HEAD^` 的基线文件单独运行 ESLint,同样有 24 个错误,确认不是本工单引入。本工单未混入无关格式化。 ### 部署 - 发布目录:`/home/goauto/releases/20260901-005500-dce4a4f` - `/home/goauto/current` 已切换到该目录。 - `goauto.service`:active。 - `127.0.0.1:8010` 与 `127.0.0.1:9527` 健康检查通过。 - 发布前确认运行中采集任务 0、执行/提交中的采购任务 0。 ### 线上浏览器回归 在 `http://185.216.248.75:9527/#/shopee-products/index?productId=17900`: 1. 重新执行颜色 AI 匹配,生成 5/6 条建议。 2. 点击“保存修改”成功;服务端日志记录连续 5 次 `PUT /api/admin/v1/shopee-products/17900/specs/mapping`。 3. 详情刷新后显示 5/6 已匹配、5 条“AI 待确认”;“保存修改”变为禁用,说明没有未保存草稿。 4. 浏览器 error/warn 日志为空。 回归只保存既有 AI 建议为待确认映射,未确认映射、未创建采购任务、订单或付款。 ### 文档影响 无长期事实变化,按工单方案跳过 Wiki 更新与同步。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#182