Files
cmautobuy/docs/admin/07-设备登记联调手册.md
T
chengmaandClaude Opus 5 62d46bf10a docs: 新增设备登记联调手册,并定案 client.name
面向 Client 开发者的实操文档,目标是让一台新设备出现在 Admin 的
客户端列表里。文中所有请求和响应都是在真实运行的 Admin 上跑出来的。

新增 docs/admin/07-设备登记联调手册.md
- 先讲清"没有注册接口,登记是 claim 的副作用"
- **重点提示 204 不是错误**:新设备第一次 claim 必然 204,
  它同时意味着登记成功。这是最容易被 Client 误判成失败的地方
- 设备号必须持久化、永不变——变了 Admin 会当成新机器,
  列表里会堆一串僵尸记录
- 设备名只在首次登记时采纳,之后 Admin 侧改名不会被覆盖。
  这个行为会让人困惑("我改了 Client 怎么 Admin 没变"),先说清楚
- 四步验证流程 + 可直接复制的 curl + 手工插测试任务的 SQL
- 7 条常见问题,含"列表里多出好几台一样的机器"这类实际会碰到的
- 列出 Client 侧待办清单,标明前两条做完就能登记成功

定案 client.name(原 [待定])
Client 设置页本来就有「设备名」输入框(deviceNameInput,50 字上限),
只是没接进 ClientInfo。Admin 仍容忍它缺失,缺了用 X-Client-Id 兜底,
所以 Client 先不发也不影响登记。

同步更新
- docs/client/04-admin-api-contract.md §5:请求示例补 client 字段,
  加"204 不是错误"的必须项,并指向本手册
- docs/README.md:两处导航加入口,Client 侧"对接 Admin"那行也指过来

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:08:58 +08:00

9.3 KiB
Raw Blame History

07 设备登记联调手册

  • 文档状态:联调用,随实现更新
  • 读者:实现 Client 侧 HttpAdminGateway 的开发者
  • 目标:让一台新 Client 出现在 Admin 的「客户端列表」里,并确认登记成功

本文所有请求和响应都是在真实运行的 Admin 上跑出来的,不是手写示例。 接口的权威定义在 Client 侧契约, 本文只讲怎么把它跑通。


1. 先理解一件事:没有注册接口

登记是领取任务的副作用。

Client 调 claim 的时候,Admin 顺手就把这台机器记下来了。 没有 /register,也没有心跳接口——这是有意的设计, 理由见 04 Client 接口实现 §3。

所以"登记新设备"这件事,Client 侧要做的就是:调一次 claim。

Client 启动
   ↓
调 POST /api/v1/client/tasks/claim(带上设备号和设备名)
   ↓
Admin:没见过这个设备号 → 新增一条记录
       见过 → 更新设备信息和最近活动时间
   ↓
返回 204(没有分给它的任务)或 200(有任务)

最容易误判的一点:新设备第一次调 claim 必然返回 204。

因为它刚登记,还没有人给它分配任务。 204 不是失败,它同时意味着登记成功了。 Client 必须把它当正常情况处理——不要报错、不要弹提示、 更不要因此触发重试风暴。


2. Client 要准备两样东西

2.1 设备号(X-Client-Id)

对应 Client 设置页那个只读的**「设备号」**输入框(现在显示"待生成")。

[必须] 规则:

  • 首次启动时生成一次(UUID 或任何全局唯一的串都行);
  • 生成后存进 app_settings,键名 admin.client_id;
  • 之后永远不变——重启、升级、改配置都不能变。

为什么不能变: Admin 是按设备号认机器的。设备号变了, Admin 会认为这是一台新机器,客户端列表里就会多出一条, 原来那条变成永远离线的僵尸记录。

换电脑、重装系统算新设备,那是对的;但同一台机器重启不能变。

2.2 设备名(client.name)

对应设置页那个可编辑的**「设备名」**输入框(50 字上限)。

  • 给人看的,比如"办公室-01"、"仓库那台";
  • 可以不填——不填的话 Admin 用设备号当显示名,不影响功能。

一个会让人困惑的行为,先说清楚:

设备名只在第一次登记时被采纳。之后操作员在 Admin 界面上把它 改成别的名字,Client 再上报也不会覆盖。

这是故意的——避免操作员精心起的名字被客户端的默认值冲掉。 所以你在 Client 那边改了设备名,发现 Admin 没变,不是 bug。


3. 请求长什么样

POST /api/v1/client/tasks/claim HTTP/1.1
Host: 127.0.0.1:8080
X-Client-Id: 7f3a1c62-9b04-4e8d-a1f2-5c7e9d0b3a11
Content-Type: application/json
Authorization: Bearer <token>
{
  "client": {
    "name": "办公室-01"
  },
  "supported_types": ["collect", "purchase"],
  "device": {
    "address": "192.168.0.173:5555",
    "platform": "android",
    "pdd_package": "com.xunmeng.pinduoduo"
  },
  "capabilities": {
    "purchase_mode": "dry_run",
    "schema_versions": [1]
  }
}
字段 必填 说明
X-Client-Id 头 是 设备号。缺了直接 400
client.name 否 设备名。缺了用设备号当显示名
supported_types 是 支持的任务类型。只写 ["collect"] 就不会拿到采购任务
device.* 否 会存进 Admin 供排查用
capabilities.purchase_mode 是 dry_run 或 live。演练模式期间固定 dry_run
Authorization 否 [待定] 认证方式未定,当前 Admin 读但不校验

4. 响应怎么处理

4.1 204 No Content —— 登记成功,暂时没活干

没有响应体。 这是新设备的正常结果,也是引擎空转时的常态。

Client 该做的:按轮询周期退避后再来,不要当成错误。

4.2 200 OK —— 领到任务了

{
  "task": {
    "id": "PDD-TEST-0001",
    "type": "purchase",
    "version": 1,
    "priority": 0,
    "payload": {
      "goods_id": "737116531267",
      "goods_url": "https://mobile.yangkeduo.com/goods.html?goods_id=737116531267",
      "options": { "color": "黑色", "size": "M码" },
      "quantity": 2,
      "max_price_cent": 4200
    },
    "created_at": "2026-08-06T08:00:00Z",
    "updated_at": "2026-08-06T08:53:20Z"
  }
}

注意三点:

  • 没有租约字段,也没有 Admin 侧状态——不用找,本来就没有;
  • options 是对象不是字符串;
  • max_price_cent 是人民币分的整数(4200 = ¥42.00)。 采购任务必然带 quantity 和 max_price_cent,这是价格保护。

4.3 400 —— 请求有问题

{
  "error": {
    "code": "MISSING_CLIENT_ID",
    "message": "缺少 X-Client-Id 请求头",
    "retryable": false,
    "request_id": "",
    "details": {}
  }
}

retryable: false 的错误不要重试,重试多少次都是一样的结果。


5. 怎么确认登记成功

第一步:起 Admin

cd D:\chengma\cmautobuy\admin
go run .

看到 Admin 已启动: http://127.0.0.1:8080 就绪。

第二步:发一次 claim

不用等 Client 写完,先用 curl 打通链路:

curl -i -X POST http://127.0.0.1:8080/api/v1/client/tasks/claim \
  -H 'X-Client-Id: test-device-001' \
  -H 'Content-Type: application/json' \
  -d '{
        "client": {"name": "联调测试机"},
        "supported_types": ["collect", "purchase"],
        "device": {"address": "192.168.0.173:5555", "platform": "android",
                   "pdd_package": "com.xunmeng.pinduoduo"},
        "capabilities": {"purchase_mode": "dry_run", "schema_versions": [1]}
      }'

预期:HTTP/1.1 204 No Content,无响应体。

第三步:在界面上确认

浏览器打开 http://127.0.0.1:8080/clients,应该看到:

名称 序列号 状态 最近活动
联调测试机 test-device-001 在线 2026-08-06T09:03:55Z

底部状态条显示 共 1 台客户端 · 在线 1 · 离线 0。

看到这一行 = 登记打通了。

第四步:让它领到一个任务(可选)

想验证 200 那条路径,得先有任务。现在还没有创建任务的界面 (要等 Excel 导入那条链路做完),手工插一条:

用 DB Browser 打开 admin/data/admin.db,执行:

INSERT INTO tasks (task_id, task_type, status, assigned_client, order_no,
                   pdd_goods_url, pdd_goods_id, pdd_options,
                   quantity, max_price_cent, created_at, updated_at)
VALUES ('PDD-TEST-0001', 'purchase', 'assigned', 'test-device-001',
        'TEST-ORDER-001',
        'https://mobile.yangkeduo.com/goods.html?goods_id=737116531267',
        '737116531267', '{"color":"黑色","size":"M码"}',
        2, 4200,
        '2026-08-06T08:00:00Z', '2026-08-06T08:00:00Z');

注意 assigned_client 要填你自己的设备号,任务只发给指定的客户端。

再调一次 claim,这次会拿到 200 和上面 §4.2 那个结构。 再调第三次又是 204——任务已经被领走了,这是对的。


6. 常见问题

现象 原因 怎么办
一直 204,列表里也没有 请求根本没到 Admin 看 Admin 控制台有没有请求日志;确认端口和地址
400 MISSING_CLIENT_ID 没带 X-Client-Id 头 它是请求头不是 body 字段
400 INVALID_BODY body 不是合法 JSON 即使没内容也要发 {},不能发空
列表里多出好几台一样的机器 设备号每次启动都在变 设备号必须持久化,见 §2.1
改了 Client 的设备名,Admin 没变 正常行为,不是 bug 见 §2.2
状态显示"离线"但客户端在跑 超过 10 分钟没调任何接口 正常。本项目有意不做心跳,执行长任务期间会显示离线
明明有任务却拿到 204 assigned_client 不是你的设备号;或 supported_types 不含该任务类型 查库确认这两项

7. Client 侧要改什么

按现在的代码(client/src/admin_gateway.py),要做这几件事:

  • requirements.txt 加 HTTP 库(requests,版本要过工单确认)
  • ClientInfo 加 name 字段 —— 设置页的「设备名」输入框已经有了, 只是没接到网关里
  • 设备号生成一次并持久化到 app_settings(键 admin.client_id), 填进设置页那个只读的「设备号」框
  • 实现 HttpAdminGateway,先只做 claim_next
  • 把 204 当正常情况返回"暂无任务",不要抛异常
  • 契约测试:Mock 和 HTTP 两个实现跑同一套用例

前两条做完就能登记成功了,后面的可以分批。


8. 还没做完的部分

能力 状态
登记新设备 可用
领取任务 可用(任务需手工插库)
提交结果 / 提交失败 可用,含幂等
创建任务的界面 未做,等 Excel 导入链路
认证 [待定],当前读 Authorization 头但不校验
改派任务 未做,需要时直接改库