{ "info": { "name": "阅读机-听书机接口 (v1)", "description": "配套 015_train_test_data.sql 与 016_api_test_data.md。\nbaseUrl 默认 http://localhost:8096/api/iot/v1(端口按实际改)。\n\n【鉴权】先发‘1.设备学员登录’,其 Tests 脚本会自动把 data.accessToken 存入集合变量 accessToken;其余需鉴权接口通过 Authorization: Bearer {{accessToken}} 使用。\n\n【免鉴权】book/list、book/download 已放开,可直接测。\n\n【下载】book/download 读取 train_book_snapshot.download_url(已指向本地 D:/tmp/books//.pdf 占位文件),请用 Send and Download 保存为文件;支持 Range 断点续传。下架书(BK-00012/BV-2、BK-00015)会返回业务错误。", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "variable": [ { "key": "baseUrl", "value": "http://localhost:8096/api/iot/v1" }, { "key": "accessToken", "value": "" } ], "item": [ { "name": "1.设备学员登录 POST /device/login", "request": { "method": "POST", "url": "{{baseUrl}}/device/login", "header": [ { "key": "Content-Type", "value": "application/json" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"userId\": 10001\n}" } }, "event": [ { "listen": "prerequest", "script": { "exec": [ "var secrets = {", " \"READER-LIB-01\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\",", " \"READER-LIB-02\": \"60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752\",", " \"READER-LIB-03\": \"688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6\"", "};", "var body = JSON.parse(pm.request.body.raw);", "var secret = secrets[body.deviceId];", "body.timestamp = Date.now();", "var raw = JSON.stringify(body);", "pm.request.body.raw = raw;", "var nonce = CryptoJS.lib.WordArray.random(16).toString();", "var stringToSign = \"POST\\n/api/iot/v1/device/login\\n\" + body.timestamp + \"\\n\" + nonce + \"\\n\" + raw;", "var sig = CryptoJS.HmacSHA256(stringToSign, secret).toString(CryptoJS.enc.Hex);", "pm.request.headers.upsert({ key: \"X-Nonce\", value: nonce });", "pm.request.headers.upsert({ key: \"X-Signature\", value: sig });" ] } }, { "listen": "test", "script": { "exec": [ "var json = pm.response.json();", "if (json && json.data && json.data.accessToken) {", " pm.collectionVariables.set('accessToken', json.data.accessToken);", " console.log('accessToken saved');", "} else {", " console.log('login failed: ' + pm.response.text());", "}" ] } } ] }, { "name": "2.设备注销 POST /device/logout", "request": { "method": "POST", "url": "{{baseUrl}}/device/logout", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{accessToken}}" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"reason\": \"REBOOT\",\n \"timestamp\": 1767621000000,\n \"nonce\": \"f6e5d4c3b2a1\"\n}" } } }, { "name": "3.设备心跳 POST /device/heartbeat", "request": { "method": "POST", "url": "{{baseUrl}}/device/heartbeat", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{accessToken}}" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"status\": \"ONLINE\",\n \"metrics\": {\"cpu\":20,\"mem\":30,\"diskFree\":10240},\n \"configVersion\": \"CV-17\",\n \"personVersion\": \"PV-226118-7\",\n \"timestamp\": 1767622000000,\n \"nonce\": \"aa11bb22cc33\"\n}" } } }, { "name": "4.阅读记录单条上报 POST /reading/record", "request": { "method": "POST", "url": "{{baseUrl}}/reading/record", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{accessToken}}" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"recordId\": \"RD-TEST-0001\",\n \"bookId\": \"BK-00012\",\n \"bookVersion\": \"BV-3\",\n \"mode\": \"read\",\n \"recordType\": \"END\",\n \"startTime\": 1767620000000,\n \"endTime\": 1767622400000,\n \"durationSec\": 1420,\n \"pageFrom\": 12,\n \"pageTo\": 46,\n \"progress\": 0.35\n}" } } }, { "name": "5.阅读记录批量上报 POST /reading/record/batch", "request": { "method": "POST", "url": "{{baseUrl}}/reading/record/batch", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{accessToken}}" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"batchId\": \"BATCH-RD-001\",\n \"timestamp\": 1767622500000,\n \"nonce\": \"b2b3c4d5e6f7\",\n \"records\": [\n {\"recordId\":\"RD-TEST-0002\",\"bookId\":\"BK-00013\",\"bookVersion\":\"BV-2\",\"mode\":\"read\",\"recordType\":\"END\",\"startTime\":1767620000000,\"endTime\":1767622400000,\"durationSec\":980,\"pageFrom\":5,\"pageTo\":22,\"progress\":0.18}\n ]\n}" } } }, { "name": "6.阅读汇总与续读进度 GET /reading/progress", "request": { "method": "GET", "url": "{{baseUrl}}/reading/progress?deviceId=READER-LIB-01", "header": [ { "key": "Authorization", "value": "Bearer {{accessToken}}" } ] } }, { "name": "7.可阅读书籍列表 GET /book/list (免鉴权)", "description": "免鉴权。可加 &bookCategory=SAFETY 过滤。无分类时只返回上架书 total=3(下架的 BK-00012/BV-2、BK-00015 不返回)。", "request": { "method": "GET", "url": "{{baseUrl}}/book/list?deviceId=READER-LIB-01" } }, { "name": "8.PDF书籍下载 GET /book/download (免鉴权)", "description": "免鉴权。download_url 已指向本地 D:/tmp/books/BK-00012/BV-3.pdf(占位文件)。请用 Send and Download 保存。支持 Range 断点续传。下架书 bookId=BK-00012&bookVersion=BV-2 会返回业务错误『图书已下架,禁止下载』。", "request": { "method": "GET", "url": "{{baseUrl}}/book/download?deviceId=READER-LIB-01&bookId=BK-00012&bookVersion=BV-3" } }, { "name": "9.下载完成回执 POST /book/download/ack", "request": { "method": "POST", "url": "{{baseUrl}}/book/download/ack", "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Authorization", "value": "Bearer {{accessToken}}" } ], "body": { "mode": "raw", "raw": "{\n \"deviceId\": \"READER-LIB-01\",\n \"bookId\": \"BK-00012\",\n \"bookVersion\": \"BV-3\",\n \"fileMd5\": \"c4ca4238a0b923820dcc509a6f75849b\",\n \"result\": \"SUCCESS\",\n \"errMsg\": \"\",\n \"timestamp\": 1767630000000,\n \"nonce\": \"cc55dd66ee77\"\n}" } } } ] }