# 数据引擎 — 平台与接口配置指南 > 适用版本:HDWL data-engine > 阅读对象:实施工程师、运维人员 > 前置知识:了解 JSON 基本格式即可 --- ## 目录 1. [概念说明](#1-概念说明) 2. [平台管理 (api_datasource_platform)](#2-平台管理) 3. [接口管理 (api_interface)](#3-接口管理) 4. [实战:新增一个平台](#4-实战新增一个平台) 5. [常见问题](#5-常见问题) --- ## 1. 概念说明 ``` 平台 (Platform) → 对接的第三方系统(如:快手电商、腾讯广告、钉钉) └── 接口 (Interface) → 平台提供的具体 API(如:订单列表、商品详情) └── 表 (Table) → 数据最终存储的数据库表 ``` **举例**: - **平台** = 快手电商 - **接口1** = 订单列表 → 数据存入 `kuaishou_order_list` 表 - **接口2** = 商品列表 → 数据存入 `kuaishou_item_list` 表 - **接口3** = 售后单列表 → 数据存入 `kuaishou_refund_list` 表 系统会按照配置的**调度周期**,自动拉取每个接口的数据并存入对应的数据库表。 --- ## 2. 平台管理 平台配置存储在 `api_datasource_platform` 表中,定义了一个第三方平台的基本信息和认证方式。 ### 2.1 基础字段 | 字段 | 类型 | 必填 | 说明 | 示例 | |------|------|------|------|------| | `platform_code` | VARCHAR | ✅ | 平台唯一编码,不能重复 | `kuaishou`、`tencent` | | `platform_name` | VARCHAR | ✅ | 平台显示名称 | `快手电商`、`腾讯广告` | | `description` | VARCHAR | ❌ | 平台描述 | `快手电商开放平台数据同步` | | `status` | VARCHAR | ✅ | 状态,`ACTIVE`=启用,`INACTIVE`=停用 | `ACTIVE` | | `api_base_url` | VARCHAR | ✅ | API 域名,接口地址会拼接在此 URL 后面 | `https://openapi.kwaixiaodian.com` | ### 2.2 认证类型 (auth_type) | 类型 | 说明 | 适用场景 | |------|------|----------| | `TOKEN` | 简单 Token 认证,放在 Header 中 | 内部系统 | | `API_KEY` | API Key 认证,Token 放在请求参数中 | **快手电商**、钉钉 | | `OAUTH2` | OAuth 2.0 认证 | 腾讯广告 | | `SIGN` | 签名认证,使用 appKey + appSecret 签名 | 部分开放平台 | | `APP_SIGNATURE` | 应用签名认证,基于请求体 MD5 | 钉钉智能薪酬 | ### 2.3 认证配置 (auth_config) `auth_config` 是一个 **JSON 对象**,根据不同的 `auth_type` 配置不同内容。 #### API_KEY 类型配置(快手电商示例) ```json { "sign_algorithm": "md5", "app_key": "ks651333099611149957", "app_secret": "JPUXG2CS3I7tqRWbKaLrYQ", "sign_secret": "7bc51baab818cf86e121a48d99ff3fe4", "token_in_query": true, "query_key": "access_token", "extra_query_params": { "timestamp": "{timestamp_ms}" } } ``` | 字段 | 说明 | |------|------| | `sign_algorithm` | 签名算法,可选 `md5`(小写输出)或 `md5_upper`(大写输出)或 `HMAC_SHA256` | | `app_key` | 平台分配的 AppKey(也叫 AppId、client_id),**快手签名必填** | | `app_secret` | 平台分配的 AppSecret,用于 OAuth 获取 Token | | `sign_secret` | 签名专用密钥(**快手特有**),平台分配,在"应用详情"中查看 | | `token_in_query` | `true`=Token 放在 URL 参数中;`false`=Token 放在 Header 中 | | `query_key` | Token 的参数名,默认 `access_token` | | `extra_query_params` | 额外需要拼接的参数,支持 `{timestamp}`(秒)、`{timestamp_ms}`(毫秒)、`{nonce}` 占位符 | > **快手签名算法**(仅供参考,代码已实现): > 1. 所有参数按字母排序,拼接成 `key1=value1&key2=value2&...` > 2. 末尾追加 `&signSecret=你的signSecret` > 3. 对整个字符串取 MD5 #### SIGN 类型配置 ```json { "sign_algorithm": "md5", "app_key": "your_app_key", "app_secret": "your_app_secret" } ``` ### 2.4 限流与重试字段 | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `rate_limit_per_minute` | INT | 100 | 每分钟最大请求次数,防止触发平台限流 | | `rate_limit_per_hour` | INT | 3600 | 每小时最大请求次数 | | `concurrency_limit` | INT | 5 | 并发请求数 | | `request_timeout_ms` | INT | 30000 | 单次请求超时时间(毫秒) | | `max_retries` | INT | 3 | 请求失败后的最大重试次数 | | `retry_delay_ms` | INT | 1000 | 重试间隔(毫秒),每次翻倍 | ### 2.5 Token 与 API Key 字段 | 字段 | 说明 | 快手示例 | |------|------|----------| | `token` | 认证 Token / Refresh Token | 快手 OAuth 返回的 `refresh_token` | | `api_key` | API Key / Access Token | 快手 OAuth 返回的 `access_token` | | `client_id` | OAuth2 Client ID | 腾讯广告的 client_id | | `client_secret` | OAuth2 Client Secret | 腾讯广告的 client_secret | --- ## 3. 接口管理 接口配置存储在 `api_interface` 表中,定义了一个平台下每个 API 的请求方式、参数、响应解析规则和存储表结构。 ### 3.1 基础字段 | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `platform_id` | INT | ✅ | 所属平台的 ID(关联 `api_datasource_platform.id`) | | `name` | VARCHAR | ✅ | 接口名称,如"订单列表" | | `code` | VARCHAR | ✅ | 接口编码,唯一标识,如 `order_list` | | `url` | VARCHAR | ✅ | API 路径,会拼接在平台 `api_base_url` 后面 | | `method` | VARCHAR | ✅ | HTTP 方法,`GET` 或 `POST` | | `status` | VARCHAR | ✅ | 状态,`active`=启用,`inactive`=停用 | | `auth_type` | VARCHAR | ✅ | 认证方式,`inherit`=继承平台配置 | ### 3.2 请求配置 (request_config) `request_config` 是一个 **JSON 对象**,定义如何构造 API 请求参数。 #### 3.2.1 完整字段说明 ```json { "page_param": "cursor", "page_size_param": "pageSize", "cursor_pagination": true, "pagination_mode": "offset", "page_size": 50, "initial_cursor": "", "method": "open.order.cursor.list", "version": 1, "signMethod": "MD5", "time_field": "updateTime", "time_field_mode": "range", "full_sync_start_time": 1700000000000, "queryType": 2, "parameters_location": "query", "body_wrapper_field": "param", "exclude_from_wrapper": ["method", "version", "signMethod"], "prefetch": { ... }, "recursive": { ... }, "row_inject": ["statisticsMonth"], "max_recursive_depth": 20 } ``` #### 3.2.2 分页配置 | 字段 | 说明 | 示例 | |------|------|------| | `page_param` | 页码/游标的参数名 | `cursor`、`page`、`offset` | | `page_size_param` | 每页条数的参数名 | `pageSize`、`page_size` | | `page_size` | 每页请求条数,覆盖全局配置 | `50` | | `cursor_pagination` | `true`=游标分页;不配置=普通页码分页 | `true` | | `pagination_mode` | `offset`=偏移量分页(`offset=(page-1)*size`);不配置=页码分页 | `offset` | | `initial_cursor` | 游标分页时的初始游标值,不配则为空字符串 | `""` | **三种分页模式对比**: | 模式 | 配置方式 | 适用平台 | 翻页方式 | |------|----------|----------|----------| | 游标分页 | `cursor_pagination: true` | 快手、钉钉 | 响应返回 cursor,下次请求带上 | | 普通分页 | 默认 | 腾讯广告 | 响应返回 totalPages,按页码翻 | | hasMore 分页 | `has_more_field` 在 response_config | 钉钉 | 响应有 hasMore 字段判断是否有下一页 | #### 3.2.3 时间过滤配置 用于增量同步——只拉取上次同步之后新增/更新的数据。 | 字段 | 说明 | |------|------| | `time_field` | 时间字段名,如 `updateTime`、`createTime` | | `time_field_mode` | 时间模式:`range`=快手模式(beginTime/endTime),`filtering`=腾讯模式(filtering 数组) | | `full_sync_start_time` | 首次全量同步的起始时间戳(**Unix 毫秒**),不配则用全局 `default_lookback_days` | | `queryType` | 快手专用:`1`=按创建时间查(90天内),`2`=按更新时间查(240天内) | > **全局配置** `config.yml` 中 `sync.default_lookback_days` 控制默认回溯天数(默认 89 天)。 #### 3.2.4 业务参数 除了上述系统级字段外,`request_config` 中其他字段都会作为**业务参数**发送给 API。 **快手示例**(`orderViewStatus`、`cpsType`、`sort` 等是业务参数): ```json { "orderViewStatus": 1, "cpsType": 1, "sort": 1, "pageSize": 50 } ``` #### 3.2.5 body_wrapper_field(快手专用) 快手 API 要求所有业务参数打包成一个 JSON 字符串,放在 `param` 字段中发送。 ```json { "body_wrapper_field": "param", "exclude_from_wrapper": ["method", "version", "signMethod"] } ``` **效果**: - 业务参数 `orderViewStatus=1, pageSize=50, sort=1` → 打包为 `param={"orderViewStatus":1,"pageSize":50,"sort":1}` - `method`、`version`、`signMethod` 保持在顶层,不被打包 #### 3.2.6 预取配置 (prefetch) 用于需要**先获取实体列表,再逐个查详情**的场景。 ```json { "prefetch": { "url": "/open/order/cursor/list", "method": "GET", "response_path": "data.orderList", "target_param": "oid", "value_field": "oid" } } ``` | 字段 | 说明 | |------|------| | `url` | 预取数据的 API 路径 | | `method` | HTTP 方法 | | `response_path` | 从响应中提取实体列表的 JSON 路径,如 `data.orderList` | | `target_param` | 将提取的值传给目标接口时使用的参数名 | | `value_field` | 从实体中取哪个字段的值,不配则传整个实体对象 | **工作流程示例**(订单详情): 1. 先调用 `/open/order/cursor/list` 获取所有订单 ID 列表 2. 对每个订单 ID,调用 `/open/order/detail?oid=xxx` 获取详情 3. 所有详情数据合并存入 `kuaishou_order_detail` 表 #### 3.2.7 递归遍历配置 (recursive) 用于树形结构数据(如钉钉部门树)。 ```json { "recursive": { "key_field": "dept_id", "target_param": "parent_id" } } ``` | 字段 | 说明 | |------|------| | `key_field` | 当前节点的 ID 字段名 | | `target_param` | 传给下级查询的参数名 | | `max_recursive_depth` | 最大递归深度,默认 20 | #### 3.2.8 参数位置控制 | 字段 | 说明 | |------|------| | `parameters_location` | `query`=参数放 URL 查询字符串;不配=GET 放 URL,POST 放 Body | #### 3.2.9 字段注入 (row_inject) 如果响应中缺少请求参数中的某些字段,可以用 `row_inject` 注入到每行数据中。 ```json { "row_inject": ["statisticsMonth"] } ``` ### 3.3 响应配置 (response_config) `response_config` 是一个 **JSON 对象**,定义如何解析 API 响应,判断成功/失败,提取数据。 ```json { "success_field": "result", "success_value": 1, "message_field": "error_msg", "list_path": "data.orderList", "cursor_field": "data.cursor", "cursor_end_marker": "nomore", "single_record": false, "has_more_field": "data.hasMore" } ``` | 字段 | 说明 | 默认值 | |------|------|--------| | `success_field` | 判断成功的字段名 | `code` | | `success_value` | 成功的值(数字) | `0` | | `message_field` | 错误消息的字段名 | `message` | | `list_path` | 数据列表的 JSON 路径,如 `data.orderList` | `data` | | `cursor_field` | 游标值的 JSON 路径,如 `data.cursor` | 无 | | `cursor_end_marker` | 游标结束标记,收到此值表示到底 | `nomore` | | `single_record` | `true`=响应是单条记录(详情接口),会自动包装成数组 | `false` | | `has_more_field` | hasMore 分页模式的判断字段路径 | 无 | #### 成功判断逻辑 ``` 读取响应的 success_field 字段 → 转成数字 → 和 success_value 比较 相等 = 成功 不相等 = 失败,取 message_field 作为错误消息 ``` **快手示例**:`result` 字段值 = `1` 表示成功 **腾讯示例**:`code` 字段值 = `0` 表示成功 #### 数据提取逻辑 ``` 1. 按 list_path 逐层进入 JSON 2. 最后一段如果是数组 → 直接作为列表 3. 最后一段是对象 → 找对象里的 list/orderList 字段 4. 如果 single_record=true → 将对象包装为单元素数组 5. 每行数据自动展平(子对象字段合并到顶层) 6. 每行附加 raw_data 字段(原始 JSON) ``` ### 3.4 表结构定义 (table_definition) `table_definition` 是 **JSON 对象**,定义目标表的表名、列结构和冲突处理。 ```json { "table_name": "kuaishou_order_list", "columns": [ { "name": "oid", "type": "BIGINT", "comment": "订单ID" }, { "name": "status", "type": "INT", "comment": "订单状态码" }, { "name": "createTime", "type": "BIGINT", "comment": "创建时间" }, { "name": "updateTime", "type": "BIGINT", "comment": "更新时间" }, { "name": "totalFee", "type": "BIGINT", "comment": "总金额(分)" }, { "name": "buyerNick", "type": "VARCHAR(100)", "comment": "买家昵称" }, { "name": "itemTitle", "type": "VARCHAR(300)", "comment": "商品标题" } ], "conflict_keys": ["oid"] } ``` | 字段 | 说明 | |------|------| | `table_name` | 数据库表名,系统会自动创建 | | `columns` | 列定义数组 | | `columns[].name` | 列名,**必须与 API 响应中的字段名一致** | | `columns[].type` | PostgreSQL 数据类型:`BIGINT`、`INT`、`VARCHAR(n)`、`TEXT`、`BOOLEAN`、`JSONB` | | `columns[].comment` | 列的注释说明 | | `conflict_keys` | 唯一键,插入时冲突则更新(UPSERT),如 `["oid"]` | > **自动建表**:系统首次同步时会自动创建表。 > **自动过滤**:只写入 `columns` 中定义的字段,多余的忽略。 > **raw_data**:每行会自动附带一个 `raw_data` 字段,保存完整的原始 JSON 响应。 --- ## 4. 实战:新增一个平台 以"快手电商"为例,完整步骤: ### 第 1 步:创建平台配置 在 `api_datasource_platform` 表插入一条记录: ```sql INSERT INTO api_datasource_platform ( tenant_id, platform_code, platform_name, description, status, api_base_url, auth_type, token, api_key, auth_config, rate_limit_per_minute, request_timeout_ms, max_retries, retry_delay_ms ) VALUES ( 1, -- 租户 ID 'kuaishou', -- 平台编码(唯一) '快手电商', -- 名�� '快手电商开放平台数据同步', 'ACTIVE', -- 状态 'https://openapi.kwaixiaodian.com', -- API 域名 'API_KEY', -- 认证类型 '你的refresh_token', -- Token(OAuth 返回) '你的access_token', -- API Key(OAuth 返回) '{...}', -- auth_config(见 2.3 节) 100, 30000, 3, 1000 -- 限流/超时/重试 ); ``` ### 第 2 步:创建接口配置 对每个需要同步的 API,在 `api_interface` 表插入一条记录: ```sql INSERT INTO api_interface ( tenant_id, platform_id, name, code, url, method, status, auth_type, request_config, response_config, table_definition ) VALUES ( 1, (SELECT id FROM api_datasource_platform WHERE platform_code='kuaishou'), '订单列表', -- 名称 'order_list', -- 编码(唯一) '/open/order/cursor/list', -- API 路径 'GET', -- HTTP 方法 'active', -- 状态 'inherit', -- 认证(继承平台) '{...}', -- request_config(见 3.2 节) '{...}', -- response_config(见 3.3 节) '{...}' -- table_definition(见 3.4 节) ); ``` ### 第 3 步:验证 系统启动后会自动: 1. 根据 `table_definition` 创建数据库表 2. 按调度周期拉取数据 3. 写入表中 --- ## 5. 常见问题 ### Q1:怎么判断数据有没有同步成功? 查看 `sync_tracker` 表,每个接口有一条记录: - `sync_status` = `success` 表示成功 - `last_sync_time` = 上次同步的时间戳 - 查看 `sync_task_log` 表可以看到每次同步的详细日志 ### Q2:怎么修改同步频率? 编辑 `config.yml`: ```yaml sync: sync_interval_minutes: 60 # 改这个,单位分钟 ``` ### Q3:接口报"签名校验失败"怎么排查? 1. 确认 `app_key`、`app_secret`、`sign_secret` 和快手后台一致 2. 确认 `access_token` 没有过期 3. 确认 `sign_algorithm` 配置正确(快手用 `md5`) 4. 查看日志中的 "签名原文" 和 "签名值",对比快手官方签名工具的结果 ### Q4:想抽取历史数据怎么办? 在接口的 `request_config` 中设置 `full_sync_start_time`(Unix 毫秒时间戳),或修改 `config.yml` 的 `sync.default_lookback_days`。 ### Q5:数据重复怎么办? 配置 `table_definition` 中的 `conflict_keys`,系统会用 **UPSERT** 模式(冲突时自动更新,不产生重复数据)。 ### Q6:如何停用某个接口? ```sql UPDATE api_interface SET status = 'inactive' WHERE code = '接口编码'; ``` --- > 📅 最后更新:2026-06-16 > 📝 如有疑问,请联系开发团队 --- ## 6. 同步机制说明 ### 6.1 同步生命周期 ``` 第 1 次同步(全量) lastSyncTime = 0 → 从 default_lookback_days 天前开始拉取 时间分片:每 7 天一个分片(如 90 天 ≈ 13 个分片循环) 完成后:记录 lastSyncTime = 数据中最大的更新时间 ↓ 第 N 次同步(增量) 读取 lastSyncTime → beginTime = lastSyncTime 只拉取上次同步之后新增/更新的数据 完成后:更新 lastSyncTime ↓ (每隔 sync_interval_minutes 分钟循环一次) ``` ### 6.2 配置项 编辑 `config.yml`: ```yaml sync: page_size: 100 # 每次分页请求条数 concurrency: 5 # 同步并发数 retry_count: 3 # 最大重试次数 sync_interval_minutes: 60 # 自动同步间隔(分钟),增量频率 compensation_interval_seconds: 300 # 失败重试扫描间隔(秒) auto_sync_enabled: true # 是否启用自动同步 sync_timeout_minutes: 120 # 单次同步超时(分钟) default_lookback_days: 89 # 首次全量回溯天数(可按接口覆盖) default_tenant_id: 1 # 租户 ID ``` | 配置项 | 说明 | 建议值 | |--------|------|--------| | `sync_interval_minutes` | 增量同步频率 | 60(1小时) | | `default_lookback_days` | 首次全量拉多少天 | 快手限制 90 天内,建议 89 | | `compensation_interval_seconds` | 失败后多久重试 | 300(5分钟) | | `auto_sync_enabled` | 是否自动跑 | 生产环境 `true` | ### 6.3 覆盖单个接口的回溯天数 在接口 `request_config` 中加入 `full_sync_start_time`(Unix **毫秒**) ```json { "full_sync_start_time": 1769200000000 } ``` ### 6.4 查看同步状态 ```sql -- 所有接口的同步状态 SELECT platform_code, interface_code, sync_status, to_timestamp(last_sync_time) AS last_sync_at FROM sync_tracker ORDER BY platform_code, interface_code; -- 最近失败记录 SELECT * FROM sync_task_log WHERE status = 'failed' ORDER BY start_time DESC LIMIT 20; ``` - `sync_status = 'success'`:上次成功 - `sync_status = 'running'`:正在跑 - `last_sync_time = 0`:还没完成过同步 ### 6.5 手动重新全量 把 `last_sync_time` 置 0,下次自动变全量: ```sql UPDATE sync_tracker SET last_sync_time = 0 WHERE platform_code = 'kuaishou' AND interface_code = 'order_list'; ``` --- > 📅 最后更新:2026-06-16