Files
affiliate_dash/docs/Rock发货平台代理接入与库存风控实施方案.md
T
yml2213 78e2fe4c6a fix(delivery): 禁用Rock二次生成二维码并治理上游110001频控报错
1. 业务防乱(专属通道锁定):提货页面一旦生成二维码后,直接禁用'重新生成二维码'按钮并锁定游戏UID输入框,杜绝Token浪费与绑定混乱;
2. 频控治理(前端3秒冷却):手动点击'检查扫码状态'增加3秒倒计时防抖冷却,且对'过于频繁/110001'错误进行平滑提示,不再触发大红报错;
3. 频控治理(后端瞬时防抖与软降级):RockService增加800ms内存并发安全防抖缓存,当上游返回110001时自动优雅降级返回等待扫码状态,不抛出HTTP 400错误。
2026-10-05 18:25:35 +08:00

33 KiB
Raw Blame History

Rock发货平台 (0666.pro) 代理接入与库存风控实施方案

编制日期:2026-10-05
指导原则:

  1. 后台全反代,买家/打手对上游完全无感(底层对接全部在后端完成,对外输出完全符合既有系统规范)。
  2. Token 一次性绑定不可换绑,设立 UID 强一致防御门禁(前置填 UID,阻断混淆旧数据,UID 不符绝对禁止领取)。
  3. 本地库存池机制,支持批量采购、安全水位预警与自动补货。
  4. 先规划设计,严格门禁验证,暂不急于修改既有 Provider。

一、 核心需求解构与风险防御矩阵

序号 需求要点 业务痛点 / 致命风险 应对防御方案 确信度
REQ-1 后台做代理,用户无感上游 若直接下发 0666 链接,买家会发现源头平台;且数据结构不一致破坏现有前端逻辑。 • 后端封装中转代理,对外暴露统一的订单提货 API;
• 二维码仅输出腾讯官方活动链接(gp.qq.com),买家端完全无第三方痕迹;
• 数据字段对齐既有 DeliveryOrderInfo 与 DeliveryBindResult。
100%
REQ-2 Token 无法换绑,绑定即作废 买家若扫错游戏账号,或乱扫码,该 Token 直接报废(21 积分/个损失),且无法解绑。 • 前置输入门禁:生成二维码前,强制买家输入/确认游戏角色 UID;
• UID 强一致校验:扫码后捕获角色 UID,不等于预期 UID 严禁发货;
• 阻断错误发货,保留 Token 供售后人工处理。
100%
REQ-3 上游旧绑定信息防混淆 0666 平台下发 Token 或刚 refresh 时可能残留历史账号信息(previous_bound_account / 历史记录),容易被误判为“已绑定”。 • 基线快照比对(Baseline Snapshotting):分配 Token 时抓取初始绑定快照;
• 仅当检测到买家扫码产生新的绑定事件且角色 UID 完全吻合时,才跃迁为 bound 状态。
100%
REQ-4 后台批量采购与统一通用库存池 提取 Token 默认统一下单为“黑色通用 Token”(对应界面 1 = 黑色),该链接本身不预先区分黑蓝,是一个通用兑换凭证。 • 建立本地统一的 rock_tokens 通用库存池,无需双池割裂;
• 后台一键采购 50 个通用 Token 存入库存;
• 发货时直接从通用池中锁定分配,零网络延迟。
100%
REQ-5 安全水位告警与自动采购 库存用尽导致订单积压失败。 • 设置通用 Token 低库存预警阈值(如低于 10 个);
• 接入系统既有通知渠道(飞书、钉钉、企微机器人等);
• 支持配置开关:低于阈值自动调用上游采购补充 50 个。
100%
REQ-6 黑蓝区分时机:绑定后发货前动态选择 买家购买不同商品(黑色ROCK或蓝色运动服),上游链接本身无区别,何时决定发放黑色还是蓝色? • 延后到发货阶段决策(Late-Binding Selection):
• 买家扫码通过 UID 强一致门禁后,系统根据订单商品的 SKU 属性,在最终调用兑换接口时自动填充对应 skin:
  - 黑色商品传 "skin": "黑色ROCK长袖T恤"
  - 蓝色商品传 "skin": "蓝色运动服上衣"
100%
REQ-7 绑定错误独立统计与追溯 买家扫错账号或扫了他人账号,虽然被系统阻断未发货,但该 Token 已无法在 0666 换绑,需明确统计损耗与售后责任。 • 独立状态与指标面板:Token 标记为 mismatch(绑定错误),后台大屏卡片高亮统计“绑错数量”;
• 全要素审计快照:完整记录买家填写的 expected_uid 与扫码实际捕获的 actual_role_id、角色名、大区、发生时间,支持一键导出与人工处理。
100%
REQ-8 Rock 自动发货全局总开关 遇到上游接口波动、积分不足、Token 缺货或价格调整时,需一键熔断。 • 配置全局熔断开关 rock_auto_delivery_enabled;
• 一旦关闭:黑色ROCK与蓝色运动服两个商品彻底停走自动发货通道,直接降级为人工打手抢单或客服处理,避免错单穿透。
100%

二、 系统架构与发货时序图

2.1 整体流程时序图(全反代 + UID 强校验)

sequenceDiagram
    autonumber
    actor Buyer as 买家 / 发货员
    participant Dash as Affiliate-Dash 后台
    participant Pool as 本地 Token 库存池
    participant Rock as 0666.pro 平台
    participant Tencent as 和平精英官方 (gp.qq.com)

    Note over Buyer, Dash: 第零阶段:全局自动发货总开关检查 (Kill Switch)
    Buyer->>Dash: 打开提货页 /delivery/:orderNo
    alt rock_auto_delivery_enabled == false (总开关已关闭)
        Dash-->>Buyer: ⚠️ 该商品自动发货维护中,已转交人工客服/打手为您处理
    else rock_auto_delivery_enabled == true (允许自动发货)
        Note over Buyer, Dash: 第一阶段:前置输入 UID 锁定
        Dash-->>Buyer: 展示商品信息,要求确认/输入游戏角色 UID
        Buyer->>Dash: 提交预期游戏 UID (例如: 4331027062)

        Note over Dash, Pool: 第二阶段:本地通用池分配 Token
        Dash->>Pool: 锁定 1 个可用的通用 Token (默认黑色通用凭证)
        Pool-->>Dash: 返回 Token 记录 (包含 redeem_code, bindUrl)
        Dash->>Dash: 记录 Token 初始状态快照 (排除上游历史旧信息)
        Dash-->>Buyer: 展示腾讯官方绑定二维码 (绝无 0666 标识)

        Note over Buyer, Tencent: 第三阶段:买家微信/QQ 扫码授权
        Buyer->>Tencent: 手机扫码授权登录并绑定角色

        Note over Dash, Rock: 第四阶段:轮询与 UID 强一致门禁
        loop 每 2~3 秒轮询
            Dash->>Rock: POST /api/user/tokens/{id}/refresh
            Rock-->>Dash: 返回 binding 信息 (role, roleId, region)
        end
        
        alt 实际 roleId != 预期 UID (扫错账号)
            Dash->>Dash: 触发硬阻断!标记 deliveryStageBindMismatch
            Dash->>Pool: 将该 Token 状态标记为 mismatch (绑定错误),记录扫码角色与时间进入统计池
            Dash-->>Buyer: ⚠️ 绑定角色与订单 UID 不符,已阻断发货,请联系客服处理
        else 实际 roleId == 预期 UID (校验通过)
            Dash->>Dash: 状态变更为 bound,核验通过
            Dash-->>Buyer: 角色匹配成功 (唉终章 / 4331027062)
            
            Note over Dash, Rock: 第五阶段:根据订单商品动态选择皮肤并兑换发货
            alt 订单购买的是黑色 ROCK
                Dash->>Rock: POST /api/redeem/{id} {"skin": "黑色ROCK长袖T恤", "currency": "幸运币", "account": "..."}
            else 订单购买的是蓝色运动服
                Dash->>Rock: POST /api/redeem/{id} {"skin": "蓝色运动服上衣", "currency": "幸运币", "account": "..."}
            end
            Rock-->>Dash: {"status": "success", "message": "领取成功"}
            Dash->>Pool: 标记 Token 状态为 redeemed,记录实际发放的 skin
            Dash-->>Buyer: 发货成功!生成发货凭证图
        end
    end

三、 本地库存模型与数据表设计

为了实现后台批量采购、库存水位控制与防错追踪,设计本地专属库存表:

3.1 Token 库存表 (rock_tokens)

所有 Token 在提取时统一默认采购为**“黑色通用 Token”**(上游类型传 1 = 黑色,即 color = 'black'),不预设皮肤,入库为通用库存。

CREATE TABLE IF NOT EXISTS `rock_tokens` (
    `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `upstream_id` BIGINT UNSIGNED NOT NULL COMMENT '0666平台的Token ID,如 151153',
    `token_jwt` TEXT NOT NULL COMMENT 'Token完整JWT串',
    `redeem_code` VARCHAR(64) NOT NULL UNIQUE COMMENT '专属兑换码哈希',
    `color` VARCHAR(16) NOT NULL DEFAULT 'black' COMMENT '采购规格: 统一为 black 通用 Token',
    `status` VARCHAR(24) NOT NULL DEFAULT 'available' COMMENT '状态: available(可用)/locked(锁定)/bound(已绑)/redeemed(已发)/mismatch(绑错待查)/abnormal(异常)/expired(过期)',
    `assigned_order_no` VARCHAR(64) DEFAULT NULL COMMENT '当前绑定的内部订单号',
    `expected_uid` VARCHAR(64) DEFAULT NULL COMMENT '买家输入的预期游戏UID',
    `actual_role_name` VARCHAR(128) DEFAULT NULL COMMENT '扫码绑定的游戏角色名',
    `actual_role_id` VARCHAR(64) DEFAULT NULL COMMENT '扫码绑定的游戏角色UID',
    `actual_region` VARCHAR(64) DEFAULT NULL COMMENT '扫码绑定的大区',
    `bind_url` TEXT DEFAULT NULL COMMENT '腾讯官方绑定链接',
    `initial_snapshot` TEXT DEFAULT NULL COMMENT '分配时的初始旧绑定快照JSON(用于防混淆)',
    `cost_points` DECIMAL(10,2) DEFAULT '21.00' COMMENT '采购消耗积分',
    `redeemed_skin` VARCHAR(64) DEFAULT NULL COMMENT '实际兑换发放的皮肤名称(如: 黑色ROCK长袖T恤 / 蓝色运动服上衣)',
    `redeemed_currency` VARCHAR(64) DEFAULT NULL COMMENT '附赠的货币类型(默认: 幸运币)',
    `redeemed_amount` INT DEFAULT 0 COMMENT '附赠的货币数量(黑=10, 蓝=14)',
    `mismatch_at` DATETIME DEFAULT NULL COMMENT '判定为绑错UID的时间戳(用于统计大屏)',
    `mismatch_reason` VARCHAR(255) DEFAULT NULL COMMENT '绑错详情说明(如: 预期UID 4331027062 与扫码 3911959065 不符)',
    `expires_at` DATETIME DEFAULT NULL COMMENT 'Token官方过期时间',
    `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX `idx_status_color` (`status`, `color`),
    INDEX `idx_assigned_order` (`assigned_order_no`),
    INDEX `idx_mismatch` (`status`, `mismatch_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Rock平台Token本地通用库存池';

3.2 Rock 平台配置表 / 系统配置扩展 (rock_config)

在系统配置项中持久化以下参数:

  • rock_auto_delivery_enabled: Rock 自动发货全局总开关(true 开启 / false 一键关闭,关闭后两款商品停走自动发货通道)
  • rock_base_url: https://0666.pro
  • rock_bearer_token: 上游当前有效的 Bearer Token(如抓包中的 05c55d8b8c...)
  • rock_username: 上游系统采购用户名(调 GET /api/me 自动获取,如 王大锤)
  • rock_account_points: 上游最新同步的积分余额(实时快照,如 8271.2)
  • rock_min_points_warning: 上游最低积分告警阈值(默认 1050.0,即至少满足一次 50 个 Token 自动补货)
  • rock_token_warning_stock: 通用 Token 告警安全水位(默认 10)
  • rock_auto_purchase_enabled: 自动补货开关(true / false)
  • rock_auto_purchase_count: 触发自动补货时单次采购量(默认 50,对应上游 count=50 黑色通用 Token)
  • rock_purchase_cooldown_minutes: 自动采购防抖冷却时间(默认 10 分钟,防并发击穿积分)

3.3 0666.pro 系统采购用户账号生命周期管理方案 (Upstream Account Lifecycle)

根据业务核验,0666.pro 平台登录方式为 Bearer Token 登录 与 用户名+验证码登录(无密码登录)。依照当前实施策略,现阶段纯采用 Bearer Token 模式直接配置接入,后续再按需扩展验证码交互:

1. 凭据录入与自动校验 (Token-Only Direct Configuration)

  • 商户鉴权机制结论: 上游 0666.pro 平台无独立固定密码,仅支持“Bearer Token 登录”与“用户名+手机短信验证码登录”。根据实施规划,先期直接采用 Token 配置方式,后续再视需要支持用户名+验证码交互。
  • 后台极简配置: 在系统设置面板中,管理员直接粘贴从 0666.pro 网页或抓包中获取的当前有效 Bearer Token(64位十六进制串):

    💡 Token 提取极简指引: 登录 0666.pro 网页后,按 F12 打开控制台,在 Application (应用程序) -> Local Storage -> https://0666.pro 中找到 yd_token 字段复制;或在控制台 Console 执行 localStorage.getItem('yd_token') 即可一键复制。

  • 即时连通性校验与自动同步: 点击【保存并测试连通】,后端立即发送 GET https://0666.pro/api/me:
    • 成功时:自动提取并展示上游用户名(王大锤)、账号状态(active)、当前可用积分(8271.2),折算展示“约可采购 393 个通用 Token”;
    • 失败时:界面提示错误详情(如凭证无效),阻止错误保存。

2. 账号健康心跳与积分余额监控 (Heartbeat & Balance Tracker)

  • 定时心跳巡检:后台定时任务(如每 10 分钟)调用 GET /api/me;
  • 大屏实时看板:
    • 采购账号:王大锤(状态:active 正常)
    • 上游剩余积分:8271.2 点(看板自动折算可用 Token 配额)
    • 最后心跳时间:实时更新
  • 低积分提前预警: 当 points < 1050.0(不足一次 50 个采购)时,通过飞书/企微/钉钉机器人推送:

    ⚠️ 【资金告警】0666.pro 平台采购账号积分不足!
    账号:王大锤 | 剩余积分:840.0 点(不足一次 50 个自动补货)
    请及时前往 0666.pro 进行充值,避免断货。

3. 凭据失效(401 Unauthorized)自动处置与熔断

  • 当采购接口返回 401(Token 到期失效或被注销)时:
    1. 系统自动软熔断:自动将 rock_auto_delivery_enabled 置为报警待查状态,黑色 ROCK 与蓝色运动服两款商品立即降级为人工打手接单/客服处理,避免错单穿透;
    2. 高危警报推送:立即向管理群推送高危紧急告警:“【紧急】0666 平台采购账号 Token 已失效,自动发货通道已自动熔断转人工,请管理员复制最新 Token 登录后台更新!”;
    3. 一键恢复:管理员登录 0666.pro 获取新 Token 粘贴保存后,连通性测试通过即可一键恢复自动发货。
  • 后续扩展计划(Phase 2):未来若需支持脱离网页获取 Token,再在后台增加“输入手机号 -> 调 /api/auth/send-code -> 接收短信验证码 -> 调 /api/auth/phone-login”的在线登录换 Token 流程。

四、 核心防护算法与业务门禁细节

4.1 旧绑定信息清洗与基线比对(Anti-Ghost-Binding)

真实抓包实锤证据 (蓝色一个发货.har): 在买家尚未扫码前(Entry 1~6),上游 refresh 接口一直返回该手机号绑过的旧账号:

  • bound_account: "总荒凉"
  • bound_account_id: "3751279035"
  • bind_changed_at: null 直到买家在手机微信真正完成扫码授权后(Entry 10),上游数据才发生跃迁:
  • bound_account: "打破虚妄的浪漫"
  • bound_account_id: "3688825401"
  • previous_bound_account: "总荒凉"(旧账号自动归入 previous)
  • bind_changed_at: "2026-10-05 14:08:02"
  • bind_change_type: "rebind"

若没有基线快照比对,系统在买家扫码前就会把旧账号“总荒凉”当作买家发货,导致灾难性货损!

算法逻辑:

type BindingSnapshot struct {
    Bound           bool   `json:"bound"`
    RoleName        string `json:"role_name"`
    RoleID          string `json:"role_id"`
    BindChangedAt   string `json:"bind_changed_at"`
}

// 检查是否发生新的真实有效扫码
func IsNewBindingValid(initialSnap BindingSnapshot, currentRefresh UpstreamRefreshResp, expectedUID string) (bool, string) {
    if !currentRefresh.Binding.Bound || currentRefresh.Binding.RoleID == "" {
        return false, "等待扫码绑定"
    }

    // 若当前刷新的绑定状态与初始分配时的历史快照完全一致,说明买家尚未真正扫码,仍是历史残留
    if initialSnap.Bound && initialSnap.RoleID == currentRefresh.Binding.RoleID && initialSnap.BindChangedAt == currentRefresh.Token.BindChangedAt {
        return false, "等待买家扫码(忽略历史残留)"
    }

    // 核心门禁:UID 必须 100% 强一致
    trimmedExpected := strings.TrimSpace(expectedUID)
    trimmedActual := strings.TrimSpace(currentRefresh.Binding.RoleID)
    if trimmedExpected != "" && trimmedActual != trimmedExpected {
        return false, fmt.Sprintf("绑定账号UID(%s)与订单预期UID(%s)不一致,严禁发货!", trimmedActual, trimmedExpected)
    }

    return true, "ok"
}

4.2 绑定错误独立统计与追溯大屏 (Mismatch Audit & Metrics)

当买家扫错账号或拿他人微信扫码导致 UID 不一致时,系统触发以下处理:

  1. Token 状态跃迁至 mismatch:
    • 记录 mismatch_at = NOW();
    • 记录 mismatch_reason = fmt.Sprintf("预期UID(%s) 与 扫码UID(%s/%s) 不一致", expectedUID, actualRoleName, actualRoleID);
    • 阻断底层兑换调用,保留该 Token 在数据库中。
  2. 后台管理大屏独立统计卡片:
    • 统计指标:COUNT(status = 'mismatch'),直观展示“绑定错误待排查 Token 数量”;
    • 列表展示维度:
      • 关联订单号 (assigned_order_no)
      • 买家填写的预期 UID (expected_uid)
      • 扫码实际角色与 UID (actual_role_name / actual_role_id)
      • 发生时间与大区
    • 支持客服人工处理:
      • 人工释放/重置:若确认买家输入失误,允许客服人工纠偏重置为 available 或重新下发;
      • 上报作废:调用上游 POST /api/user/tokens/{id}/report 标记为 abnormal 归档。

4.3 全局自动发货总开关与降级熔断机制 (Kill Switch)

针对黑色 ROCK 与蓝色运动服两款商品,设立全局软熔断总开关 rock_auto_delivery_enabled:

  1. 开关位置:商户后台 / 平台设置中的一键 Switch 开关。
  2. 熔断效果:
    • 当开启 (true) 时:正常走全自动反代发货链路(分配 Token -> 出示二维码 -> 扫码强校验 -> 自动兑换发货)。
    • 当关闭 (false) 时:
      • 黑色 ROCK 和蓝色运动服两款商品彻底脱离自动发货流程;
      • 订单状态保留在 paid,自动发货接口直接返回:
        {
          "can_ship": false,
          "cannot_ship_reason": "当前该商品自动发货通道维护中,已转交人工客服/打手为您处理"
        }
        
      • 绝不调用 0666.pro 消耗 Token 或积分,由人工打手在接单平台抢单核验发货,或由客服人工处理;
      • 用于应对上游故障、Token 缺货、价格调整或恶意攻击时的秒级止血。

五、 库存管理、安全水位预警与自动采购逻辑

5.1 批量采购与入库流程

  1. 管理员在后台点击【采购 50 个黑色 Token】;
  2. 服务端带上 rock_bearer_token,向 https://0666.pro/api/user/tokens/claim 发送:
    {"color": "black", "count": "50"}
    
  3. 上游返回 50 个 Token 数组,事务批量写入 rock_tokens 表,status = 'available';
  4. 记录本次采购消耗的积分与操作日志。

5.2 水位巡检与告警通知

  1. 触发时机:
    • 订单每次消耗锁定 Token 时;
    • 后台定时巡检 Cron(如每 5 分钟)。
  2. 判断逻辑: \text{可用库存} = \operatorname{COUNT}\left(\text{status} = 'available' \land \text{color} = \text{target\_color}\right)
    • 若 $\text{可用库存} \le \text{告警阈值}$:
      • 发送机器人告警通知(复用系统现有的飞书/钉钉/企业微信 webhook):

        【库存告警】Rock平台黑色Token库存告急!
        当前可用库存:4 个(预警阈值:10 个)
        请及时确认上游积分或检查自动补货状态。

      • 若开启了 rock_auto_purchase_enabled:
        • 检查是否在冷却期内(距上次自动采购时间 \ge 10 分钟);
        • 触发自动采购任务,调用 claim 补充 50 个;
        • 采购成功后发送补货成功通知。

六、 实施规划路线图(分步推进)

[Phase 1: 数据模型与库存池] -> [Phase 2: 采购与水位监控] -> [Phase 3: 反向代理与UID门禁] -> [Phase 4: Provider集成]
- 创建 rock_tokens 数据表      - 实现手动采购API           - 提货页输入UID前置流程        - 实现 RockProvider 接口
- 系统配置项拓展             - 接入飞书/企微低库存预警     - 上游旧数据过滤与比对         - 接入系统统一发货工作台
                             - 自动补货定时任务与冷却控制   - 强一致校验与硬阻断
  • 第一阶段(数据底座):创建 rock_tokens 数据结构与配置项存储,打通 0666.pro 的 Claim 接口。(已完成)
  • 第二阶段(库存与安全):在后台管理界面增加 Rock 库存面板,支持采购 50 个、库存查看、低水位告警与自动补货。(已完成)
  • 第三阶段(反代与安全门禁):实现代理转发与 UID 校验拦截器,杜绝因扫错号报废 Token。(已完成)
  • 第四阶段(业务无缝收口):完成标准 Provider 适配,系统无缝接管。(已完成)

七、 工程落地进度与实测验证记录 (Implementation Audit)

7.1 落地成果交付清单

模块层级 文件路径 核心功能与职责 状态
SQL 迁移 backend/internal/database/migrations/012_rock_fulfillment.sql 创建 rock_configs 配置表、rock_tokens 通用库存表,初始化黑色ROCK与蓝色运动服目录数据 ✅ 已就绪
数据模型 backend/internal/model/rock.go 定义 RockConfig 与 RockToken 结构体及常量映射 ✅ 已就绪
通信客户端 backend/internal/service/rock_client.go 封装 0666.pro 平台全部 REST 接口 (GetMe, Claim, Refresh, Redeem, etc.) ✅ 已就绪
库存与风控 backend/internal/service/rock_service.go 实现库存行锁分配、Anti-Ghost 基线比对、UID强一致阻断、自动补货巡检与 mismatch 解冻 ✅ 已就绪
履约渠道 backend/internal/service/provider_rock.go 实现统一 FulfillmentProvider 接口,支持动态判定皮肤与腾讯官方流水提取 ✅ 已就绪
后台 API backend/internal/handler/rock.go 提供配置查询/更新、测试连通、一键采购 50 个、库存分页与重置接口 ✅ 已就绪
前端 API frontend/src/api/index.ts 增加 rockApi 与相关 TypeScript 类型声明 ✅ 已就绪
管理大屏 frontend/src/pages/PlatformRock.tsx 实现自动发货总开关、指标看板、Token 配置与连通测试、库存与错单审计列表 ✅ 已就绪
菜单与路由 frontend/src/App.tsx, MainLayout.tsx 注册 /platform-rock 路由与侧边栏商品管理子菜单 ✅ 已就绪
单元测试 backend/internal/service/provider_rock_test.go 覆盖软熔断、Anti-Ghost、UID不匹配阻断、黑蓝动态兑换、采购与连通测试 ✅ 100% 通过

7.2 自动化测试结果记录

  • 后端单元测试:go test -v ./internal/service -run TestRock
    • TestRockProvider_KillSwitch: PASS (0.41s)
    • TestRockProvider_AntiGhostAndUIDMismatch: PASS (0.28s)(已包含角色名正确读取验证)
    • TestRockProvider_SubmitBlueAndBlack: PASS (0.25s)(已包含兑换发货 Bearer 鉴权头校验)
    • TestRockService_StatsAndPurchase: PASS (0.23s)(已包含真实上游字符串 points 反序列化验证)
  • 后端全量测试:go test ./... -> 全部通过 (exit code 0)
  • 前端静态构建:npm run build -> tsc -b && vite build 成功通过 (exit code 0)

7.3 实测抓包逆向排障与修复记录(基于平台实际测试-1.har 铁证)

证据分类审计表

维度 内容详情 确信度
已知 (Known) 1. 用户实际发货报错:400: 调用上游兑换失败: 上游兑换发货接口返回错误码 401: {"error":"请先登录"};
2. 用户发货页显示角色名称为 -,仅显示 UID。
100% (有 HAR 报文)
未知 (Unknown) 1. 为何兑换接口返回 401?是否缺少 Header 还是 Cookie?
2. 为什么 UID 识别出来了,角色名却没有获取到?
已探明
目标 (Goal) 1. 查清发货兑换请求与刷新接口的准确协议报文;
2. 修复角色名称映射;
3. 修复兑换鉴权,实现发货成功交付。
100% 达成

关键技术发现与修复对齐:

  1. 角色名称缺失根因:
    • 抓包分析发现:0666.pro 的 /api/user/tokens/:id/refresh 与 /api/redeem/:code 响应中根本没有 binding 对象,所有的扫码角色信息直接位于 token 根对象下:
      • token.bound_account:买家真实游戏角色名(例如 "感性的洁少");
      • token.bound_account_id:买家游戏角色 UID;
      • token.region:登录渠道(例如 "安卓-微信");
      • token.status:绑定状态("bound")。
    • 修复:重构 RockTokenData 并增加 GetRoleName()、GetRoleID(),将角色名正确回填至 ProviderBindResult.RoleName 与数据库,彻底解决“角色名显示为 -”的问题。
  2. 兑换发货 401 根因:
    • 抓包分析发现:POST https://0666.pro/api/redeem/:id 接口受到商户认证中间件保护,必须携带请求头 Authorization: Bearer <yd_token>,且请求体 account 字段必须传入买家真实角色名。原代码漏设了该请求头导致被拒。
    • 修复:在 RedeemSkin 中接收并注入 Authorization: Bearer <bearerToken> 请求头,且 account 优先取 token.ActualRoleName。
  3. 单测防护覆盖:
    • 更新 TestRockProvider_AntiGhostAndUIDMismatch,断言扫码成功后 RoleName 必须准确提取为玩家角色名;
    • 更新 TestRockProvider_SubmitBlueAndBlack,若未携带 Bearer 鉴权头则模拟 401 拒绝,断言发货请求必须 100% 鉴权通过。

7.4 平台实际发货 HAR(黑色平台发货的, 自己的不行.har)报文深度比对与最终闭环

证据分类审计表

维度 内容详情 确信度
已知 (Known) 1. 用户使用 0666.pro 原生管理台发货黑色 ROCK 成功,状态码 200;
2. 发货报文完整捕获于 /Users/yml/Desktop/抓包/rock相关/黑色平台发货的, 自己的不行.har;
3. 发货成功响应体为 {"token":{...},"status":"success","message":"领取成功"},无 delivery 包装字段。
100% (有 HAR 报文证实)
未知 (Unknown) 1. 0666.pro 兑换成功后返回的 JSON 结构是否与之前预期一致?
2. 除 Bearer Token 外,是否校验 Origin / Referer / Accept 请求头?
已探明
目标 (Goal) 1. 100% 字节级对齐 0666.pro 发货请求头与响应反序列化结构;
2. 修复原代码中误假设的 redeemResp.Delivery 字段,杜绝反序列化截断或空指针;
3. 验证通过并提交 Git。
100% 达成

报文镜像比对表 (Side-by-Side Wire Protocol Diff)

POST /api/redeem/151237 HTTP/1.1
Host: 0666.pro
Authorization: Bearer 05c55d8b8c38cac0c388db2615a0e3eed5a53c1eaecdee5cf8924b2a814b1958
Content-Type: application/json
Origin: https://0666.pro
Referer: https://0666.pro/
Accept: */*

{"skin":"黑色ROCK长袖T恤","currency":"幸运币","account":"谢总腰死你"}

HTTP/1.1 200 OK
Content-Type: application/json

{
  "token": {
    "id": 151237,
    "redeem_code": "9d93ac2dd9e42ef5a22bf3d8cd9c3ed5",
    "status": "redeemed",
    "bound_account": "谢总腰死你",
    "bound_account_id": "3892548310",
    "redeem_skin": "黑色ROCK长袖T恤",
    "redeem_currency": "幸运币",
    "redeemed_at": "2026-10-05 16:23:33"
  },
  "status": "success",
  "message": "领取成功"
}

关键修复落地点:

  1. 请求头指纹对齐:在 RedeemSkin 中补齐 Origin: https://0666.pro、Referer: https://0666.pro/ 以及 Authorization: Bearer <token>;
  2. 响应结构体重构:将 RockRedeemResponse 从臆想的 delivery 对象重构为真实结构(包含 Token RockTokenData、Status string、Message string),并提供 IsSuccess() 方法判定;
  3. FulfillID 兜底流:官方单号提取优先从 token.upstream_fulfill_id 读取,若兑换后无单独 ID 则平滑兼容;
  4. 编译与单测:全量单元测试与编译均已 100% 通过。

7.5 “提货页补货中与发货报错”死锁漏洞排查记录(基于自身的补货中, 但是后台正常.har 铁证)

证据分类审计表

维度 内容详情 确信度
已知 (Known) 1. 用户反馈:自己的发货页面一直提示“补货中”,后台发货一直报错拦截,但上游 0666.pro 平台却可以正常发货;
2. 抓包证实 Token 152317 绑定正常且在上游已成功发货(账号:屛堃,UID:3640883661);
3. 数据库中订单 33 已完成发货,可用 Token 数量正好归零 (AvailableStock = 0)。
100% (有 HAR 报文与 DB 记录双重佐证)
未知 (Unknown) 为何订单明明已分配 Token 且绑定成功,提货页与发货接口仍强制判定为不可发货并提示“补货中”? 已探明
目标 (Goal) 修复 PrepareDelivery 状态机判定,订单一旦成功预占分配 Token,无论池子空闲库存是否为 0,均允许正常进入扫码与发货履约流程。 100% 达成

致命逻辑盲区根因解构:

  1. 死锁链条:
    • 当一笔订单分配了池中最后一个 Token 后,数据库中 status = 'available' 的空闲 Token 数量变为 0;
    • 买家扫码授权后,提货页轮询或点击发货,外层均调用 PrepareDelivery 进行发货前瞻校验;
    • 原代码无条件执行:
      if stats.AvailableStock <= 0 {
          return &DeliveryOrderState{CanShip: false, CannotShipReason: "当前商品库存补充中..."}
      }
      
    • 原逻辑完全忽略了当前订单其实早就成功预占了专属 Token!
    • 导致提货页直接弹窗横幅提示“当前商品库存补充中”,并在买家点击发货时被 if !info.CanShip 硬性拦截报 400 错误!
    • 此时由于上游 0666.pro 已经完成微信扫码绑定,用户前往 0666.pro 官方后台点击发货自然能够成功,造成了“自己系统报补货中,但官方后台发货正常”的假象。
  2. 修复落地:
    • 在 PrepareDelivery 中增加专属已占库存识别:如果当前订单号已存在 using 或 bound 状态的 Token,判定为库存已锁定,豁免空闲库存校验;
    • 针对未分配 Token 的新订单,在空闲库存不足时若开启了自动采购,即刻触发异步补货巡检;
    • 在 ClaimTokens 与 RefreshToken 中补齐 Origin 与 Referer 头。
  3. 回归测试门禁:
    • 新增单元测试 TestRockProvider_PrepareDelivery_ZeroStockWithAssignedToken:
      • 断言 1:空闲库存为 0 时,新订单被正确拦截并提示“库存补充中”;
      • 断言 2:空闲库存为 0 时,已分配 Token 的订单必须 100% 允许正常发货(CanShip = true)。
    • 包含新增用例在内的 5 项 Rock 专项测试与全量 service 测试全部 100% PASS。

7.6 提货页面二次绑定禁用与上游 110001 频控防抖治理

证据分类审计表

维度 内容详情 确信度
已知 (Known) 1. Rock 平台生成的二维码与 Token 属于 1:1 强绑定关系,多次调用会导致 Token 浪费或绑定覆盖;
2. 用户手动点击“检查扫码状态”时频繁触发 400 报错:未知错误码: (110001) 抱歉,请求过于频繁,请稍后再试!谢谢!,而自动轮询正常。
100% (有实测报错报文)
未知 (Unknown) 为什么自动轮询正常而手动点击报错? 已探明:自动轮询每 2.5 秒触发一次,手动点击与定时器极易并发,使 0666.pro 瞬间接收多笔相同 Token 的 refresh 请求触发 WAF 限流。
目标 (Goal) 1. 禁用提货页面“重新生成二维码”按钮,锁定专属通道;
2. 后端建立 800ms 瞬时防抖缓存与 110001 软降级;
3. 前端增加 3 秒倒计时冷却与友好提示。
100% 达成

落地措施:

  1. 提货页防抖与单次专属锁定(frontend/src/pages/Delivery.tsx):
    • bindResult 生成后,按钮变为“专属二维码已生成”并直接处于 disabled 状态;
    • 游戏 UID 输入框置灰禁用,防止中途修改;
    • 手动点击“检查扫码状态”增加 3 秒冷却倒计时(检查扫码状态 (3s)),错误处理中对“过于频繁/110001”进行平滑文案提示,不再弹出大红错误框。
  2. 后端瞬时缓存与错误降级(backend/internal/service/rock_service.go):
    • 在 RockService 中维护并发安全防抖缓存 refreshCache sync.Map(800ms 窗口);
    • 当遇到上游 110001 频控响应时,执行平滑兜底,返回正在等待扫码,不抛出 HTTP 400 异常。
  3. 验证结果:
    • 前后端静态编译构建与 5 项 Rock 单元测试全部通过。