# API Documentation Base URL: ```text http://: ``` Response content type: ```text application/json; charset=utf-8 ``` ## Authorization 所有 API 都要求固定的 `Authorization` 请求头。 配置文件: ```yaml auth: secret: "your-fixed-authorization-secret" ``` 请求示例: ```http Authorization: your-fixed-authorization-secret ``` 说明: - 服务端会把 `Authorization` 头的原始值与 `auth.secret` 做精确匹配 - 如果你想使用 `Bearer xxx` 风格,也可以直接把 `auth.secret` 配成完整的 `Bearer xxx` 未授权响应: ```json { "error": "unauthorized" } ``` ## Logging 服务端会输出两级日志: - `WARNING` - `ERROR` 当前会重点记录: - 未授权访问 - 参数错误 - 数据库相关失败 - 图片查找失败 当图片不存在时,日志里会带上尝试过的完整路径,便于排查 Windows 部署目录问题。 ## 1. Health Check `GET /healthz` 用途: - 检查 API 进程是否存活 - 检查数据库连接是否可用 成功响应: ```json { "ok": true } ``` ## 2. Query Records `GET /api/v1/records` ### 2.1 增量同步模式 不传 `id_start` / `id_end` 时,接口按当前游标做增量读取: - 条件:`ID > cursor` - 排序:`ORDER BY ID ASC` - 默认 `limit=100` - 默认 `update_cursor=true` - 如果查到数据且 `update_cursor=true`,游标推进到本次结果最后一条记录的 `ID` - 返回结果会自动补上主表里的 `KhID`,并额外附带客户表 `dbo.B_Khzl` 的客户信息 - 返回结果会根据客户表 `KHLbID` 自动关联地区表 `dbo.B_Khlb`,并平铺返回 `area` - 返回结果也会根据订单表 `HpID` 自动关联布料表 `dbo.B_Hpzl`,并平铺返回 `HpName` 参数: - `update_cursor`: 可选,布尔值,默认 `true` - `limit`: 可选,正整数,默认 `100` 示例: ```http GET /api/v1/records Authorization: your-fixed-authorization-secret ``` ```http GET /api/v1/records?update_cursor=false&limit=20 Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "incremental", "cursor_before": 1200, "cursor_after": 1250, "origin_cursor": 1000, "last_record_id": 1250, "updated": true, "count": 50, "records": [ { "ID": 1201, "KhID": 88, "BianHaoID": "...", "area": "华东地区", "HpName": "某某布料", "customer": { "KhID": 88, "KhName": "某某客户" } } ] } ``` 字段说明: - `mode`: 固定为 `incremental` - `cursor_before`: 本次请求开始前的游标 - `cursor_after`: 本次请求完成后的游标。如果 `update_cursor=false`,这里会返回本次结果最后一条记录的 ID,但不会实际写入状态文件 - `origin_cursor`: 最近一次手工修改游标前的值;自动增量同步不会改它 - `last_record_id`: 本次返回结果中的最后一条记录 ID;无数据时不存在 - `updated`: 本次是否实际更新了游标状态 - `count`: 返回记录数 - `records[].KhID`: 主表记录中的客户 ID - `records[].customer`: 客户表补充信息,当前默认包含 `KhID` 和 `KhName` - `records[].area`: 客户地区,来自 `dbo.B_Khlb` 的 `MingCheng` - `records[].HpName`: 布料表 `dbo.B_Hpzl` 中关联到的布料名称 ### 2.2 范围查询模式 传了 `id_start` 和 `id_end` 时,接口进入范围查询模式: - 条件:`ID >= id_start AND ID <= id_end` - 排序:`ORDER BY ID ASC` - 不会更新游标 - 必须显式传 `update_cursor=false` 参数: - `id_start`: 必填,非负整数 - `id_end`: 必填,非负整数 - `update_cursor`: 必填,且必须为 `false` - `limit`: 可选,正整数,默认 `100` 示例: ```http GET /api/v1/records?id_start=2000&id_end=2100&update_cursor=false Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "range", "cursor_before": 1250, "cursor_after": 1250, "origin_cursor": 1000, "last_record_id": 2050, "updated": false, "count": 51, "id_start": 2000, "id_end": 2100, "records": [ { "ID": 2000, "BianHaoID": "..." } ] } ``` ### 2.3 参数校验规则 - `limit` 必须大于 0 - `id_start` 和 `id_end` 必须同时出现 - `id_start` 和 `id_end` 必须是非负整数 - `id_start` 不能大于 `id_end` - 范围查询模式必须显式传 `update_cursor=false` ## 3. Query Current Order Snapshot `GET /api/v1/records/by-order` 用途: - 按 `external_order_id` 精确查询当前整单快照 - 返回该 `BianHaoID` 下当前全部 records - 不读取 cursor,也不推进 cursor - 返回字段会继续附带现有的 `customer`、`area`、`HpName` 参数: - `external_order_id`: 必填,字符串,精确对应主表 `D_KhDhd.BianHaoID` 示例: ```http GET /api/v1/records/by-order?external_order_id=KD20432358 Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "snapshot", "external_order_id": "KD20432358", "status": "active", "snapshot_at": "2026-04-16T10:12:34Z", "total_count": 3, "records": [ { "ID": 1000001, "BianHaoID": "KD20432358", "KhID": "KH00999", "HpName": "120克本白四面弹单定", "area": "周边", "customer": { "KhID": "KH00999", "KhName": "鸿烨服饰" } } ] } ``` 字段说明: - `mode`: 固定为 `snapshot` - `external_order_id`: 当前查询的订单号 - `status`: 当前快照状态;查询命中时固定为 `active` - `snapshot_at`: 服务端生成本次快照响应的时间 - `total_count`: 当前订单快照下 records 数量 - `records`: 当前订单下的全部 records,字段宽度与现有 `GET /api/v1/records` 保持一致 未命中响应示例: ```json { "external_order_id": "KD20432358", "status": "not_found", "message": "未找到该 external_order_id 对应的订单" } ``` ## 4. Query Customer Orders `GET /api/v1/records/by-customer` 用途: - 按客户名精确查询该客户名下全部订单 - 底层先查询 `D_KhDhd` 明细,再按 `BianHaoID` 聚合为订单主体 - 每个订单主体下的明细结构与现有 `GET /api/v1/records/by-order` 完全一致 - 不读取 cursor,也不推进 cursor - 结果按配置项 `customer_orders.sort_column` 倒序排列,默认 `KdRiQi` 参数: - `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName` 示例: ```http GET /api/v1/records/by-customer?customer_name_b64=6bi_54OI5pyN6aWw Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "customer_orders", "customer_name": "鸿烨服饰", "status": "active", "snapshot_at": "2026-05-09T10:12:34Z", "total_orders": 2, "orders": [ { "mode": "snapshot", "external_order_id": "KD20432358", "status": "active", "snapshot_at": "2026-05-09T10:12:34Z", "total_count": 2, "records": [ { "ID": 1000001, "BianHaoID": "KD20432358", "KhID": "KH00999", "HpName": "120克本白四面弹单定", "area": "周边", "customer": { "KhID": "KH00999", "KhName": "鸿烨服饰" } } ] } ] } ``` 字段说明: - `mode`: 固定为 `customer_orders` - `customer_name`: 当前查询的客户名 - `status`: 查询命中时固定为 `active` - `snapshot_at`: 服务端生成本次响应的时间 - `total_orders`: 当前客户名下聚合后的订单数 - `orders`: 订单列表;每个订单元素的结构与 `GET /api/v1/records/by-order` 返回结构保持一致 未命中响应示例: ```json { "customer_name": "鸿烨服饰", "status": "not_found", "message": "未找到该 customer_name 对应的订单" } ``` 配置: ```yaml customer_orders: sort_column: "KdRiQi" ``` - `sort_column` 用于控制订单聚合结果的排序字段,默认值为 `KdRiQi` ## 5. Query Customer List `GET /api/v1/customers` 用途: - 按客户主档表 `dbo.B_Khzl` 拉取客户列表 - 每次固定返回 `10` 个客户 - 只返回 `KhID` 和 `KhName` - 用于外部系统按客户维度做同步 - 使用游标参数 `cursor_id` 续拉,不使用 `page` / `pageSize` 排序与游标规则: - 底层按 `ZZRQ ASC, KhID ASC` 排序 - `ZZRQ` 越早的客户越先返回,避免从新到旧翻页时遗漏新数据 - `cursor_id` 传上一页最后一条客户的 `KhID` - 服务端会先查出该 `KhID` 对应的 `ZZRQ`,再从 `(ZZRQ, KhID)` 这个排序位置之后继续取下一批 `10` 条 - 如果多个客户 `ZZRQ` 相同,会继续用 `KhID` 做稳定次序 参数: - `cursor_id`: 可选,上一页最后一条客户的 `KhID` 示例: ```http GET /api/v1/customers Authorization: your-fixed-authorization-secret ``` ```http GET /api/v1/customers?cursor_id=KH01485 Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "customers", "cursor_id": "KH01485", "next_cursor_id": "KH01495", "snapshot_at": "2026-05-14T15:00:00Z", "count": 10, "customers": [ { "customer_id": "KH01486", "customer_name": "A亿佳服饰" } ] } ``` 字段说明: - `mode`: 固定为 `customers` - `cursor_id`: 本次请求使用的游标;首批为空 - `next_cursor_id`: 本页最后一条客户的 `KhID`;下一页继续传它即可 - `snapshot_at`: 服务端生成本次响应的时间 - `count`: 当前返回客户数,最大固定为 `10` - `customers[].customer_id`: 客户 ID,对应 `dbo.B_Khzl.KhID` - `customers[].customer_name`: 客户名称,对应 `dbo.B_Khzl.KhName` 未命中游标响应示例: ```json { "cursor_id": "KH99999", "status": "not_found", "message": "未找到该 cursor_id 对应的客户" } ``` ## 6. Query I_Sale Records By BianHaoID `GET /api/v1/i-sale/by-bianhao` 用途: - 按 `BianHaoID` 查询 `dbo.I_Sale` 中的业务明细记录 - 为收款和退款记录补充对应业务单据的信息 - 返回 `I_Sale` 的全量字段 - 不读取 cursor,也不推进 cursor 注意: - 同一个 `BianHaoID` 在 `I_Sale` 中可能命中多条明细行 - 因此该接口返回的是 `records[]`,不是单对象详情 参数: - `bianhao_id`: 必填,精确匹配 `dbo.I_Sale.BianHaoID` 示例: ```http GET /api/v1/i-sale/by-bianhao?bianhao_id=XT20203911 Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "i_sale_records", "bianhao_id": "XT20203911", "status": "active", "snapshot_at": "2026-05-14T15:10:00Z", "total_count": 1, "records": [ { "BianHaoID": "XT20203911", "DanType": "客户退货单", "KhID": "KH01204" } ] } ``` 字段说明: - `mode`: 固定为 `i_sale_records` - `bianhao_id`: 当前查询的业务单号 - `status`: 查询命中时固定为 `active` - `snapshot_at`: 服务端生成本次响应的时间 - `total_count`: 当前 `BianHaoID` 命中的 `I_Sale` 明细行数 - `records`: `I_Sale` 全量字段明细列表 未命中响应示例: ```json { "bianhao_id": "XT404", "status": "not_found", "message": "未找到该 bianhao_id 对应的 I_Sale 记录" } ``` ## 7. Query I_Sale Records By Customer `GET /api/v1/i-sale/by-customer` 用途: - 按客户 ID 查询 `dbo.I_Sale` 中的业务明细记录 - 用于补足按客户统计时对 `I_Sale` 的直接拉取能力 - 不分页、不使用游标;一次返回当前客户在指定分类下的全部命中记录 - 返回字段不是 `I_Sale` 全 119 列,而是“核心标识 + 全部金额字段 + 全部数量字段 + 备注字段” 当前分类策略: - `sale`:只取 `DanType = '成品销售单' AND BianHaoID LIKE 'XS%'` - `sale_return`:只取 `DanType = '客户退货单' AND BianHaoID LIKE 'XT%'` 当前实现决策: - 用户明确接受低频调用,因此本接口不做分页和游标 - 但为了避免把 `I_Sale` 全 119 列直接暴露给同步方,当前只返回与统计/业务核对最相关的字段组 - 该字段组已结合项目内 `I_SALE_FIELD_ANALYSIS.md` 与线上 `db/columns` 验证 参数: - `customer_id`: 必填,精确匹配 `dbo.I_Sale.KhID` - `category`: 必填,当前只支持 `sale`、`sale_return` 示例: ```http GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale Authorization: your-fixed-authorization-secret ``` ```http GET /api/v1/i-sale/by-customer?customer_id=KH00308&category=sale_return Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "i_sale_customer_records", "customer_id": "KH00308", "category": "sale", "status": "active", "snapshot_at": "2026-05-14T20:00:00Z", "total_count": 2, "records": [ { "SubID": 1, "BianHaoID": "XS20367431", "DanType": "成品销售单", "KhID": "KH00308", "RiQi": "2026-05-14T00:00:00Z", "KdRiQi": "2026-05-14T19:08:23Z", "JieSunFS": "欠款", "HpID": "HP00001", "JianShu": "1.00", "ShuLiang": "20.00", "ShuLiangT": "20.00", "DanJia": "32.000000", "JinE": "640.000000", "DingJin": "0.00", "YfJinE": "0.00", "SfJinE": "0.00", "ZkJinE": "0.00", "LjQK": "0.00", "BeiZhu": "", "BeiZhuC": "", "BeiZhuD": "", "MeoD": "普通单据" } ] } ``` 字段说明: - `mode`: 固定为 `i_sale_customer_records` - `customer_id`: 当前查询的客户 ID - `category`: 当前查询的分类 - `status`: 查询命中时固定为 `active` - `snapshot_at`: 服务端生成本次响应的时间 - `total_count`: 当前客户在该分类下命中的 `I_Sale` 明细行数 - `records`: 当前字段集包含以下几类字段 核心标识字段: - `SubID` - `BianHaoID` - `DanType` - `KhID` - `RiQi` - `KdRiQi` - `JieSunFS` - `HpID` - `JiJiaDW` 数量相关字段: - `JianShu` - `ShuLiang` - `ShuLiangZ` - `ShuLiangK` - `ShuLiangS` - `JianShuT` - `ShuLiangT` - `ShuLiangZT` - `ShuLiangKT` - `ShuLiangST` - `Sl1` ~ `Sl10` 金额相关字段: - `DingJin` - `YfJinE` - `SfJinE` - `ZkJinE` - `LjQK` - `DanJia` - `JinE` - `DanJiaT` - `JinET` - `DanJiaCB` - `JinECB` - `JinE_SL` 备注相关字段: - `BeiZhu` - `BeiZhuC` - `BeiZhuD` - `MeoA` - `MeoB` - `MeoC` - `MeoD` 未命中响应示例: ```json { "customer_id": "KH00308", "category": "sale", "status": "not_found", "message": "未找到该 customer_id 和 category 对应的 I_Sale 记录" } ``` 参数错误: - `customer_id` 为空时返回 `400` - `category` 非 `sale` / `sale_return` 时返回 `400` ## 7. Query Customer Finance Records `GET /api/v1/finance/by-customer` 用途: - 按客户名精确查询该客户名下的财务记录 - 当前销售/销退只认 `dbo.I_Sale` - 当前收款/退款只认 `dbo.F_Skd` - 支持按记录类型筛选,并支持控制是否包含真实资金变动、是否包含挂账/欠款调整 - 不读取 cursor,也不推进 cursor 参数: - `customer_name_b64`: 必填,客户名的 Base64URL 编码;精确匹配客户表 `dbo.B_Khzl.KhName` - `record_types`: 可选,逗号分隔;支持 `sale`、`sale_return`、`receipt`、`refund`;不传默认全部 - `include_cash_movement`: 可选,布尔值;默认 `true` - `include_adjustments`: 可选,布尔值;默认 `false` - `filter_sk`: 可选,布尔值;默认 `false`;当前 `receipt` 口径下保留该参数但不生效 当前口径: - `sale`: `I_Sale.DanType = '成品销售单'` - `sale_return`: `I_Sale.DanType = '客户退货单'` - `receipt`: 仅纳入 `F_Skd.BianHaoID LIKE 'SK%'` 的收款流水,不纳入 `XS%` 记录 - `refund`: `F_Skd.sType = 1 AND F_Skd.BianHaoID LIKE 'XT%'` - `receipt` 的返回金额字段仍保留 `F_Skd.FkJinE`、`F_Skd.ZkJinE` 等原始值,但当前口径不再使用 `FkJinE` 作为筛选条件 - `refund` 的统计和筛选金额字段为 `F_Skd.YfJinE` - `include_cash_movement` 与 `include_adjustments` 当前仅影响 `refund`;`receipt` 统一按 `SK%` 全量统计 - `include_cash_movement=true` 时,`refund` 取 `YfJinE < 0` - `include_adjustments=true` 时,`refund` 额外包含 `YfJinE = 0` 的挂账/欠款调整记录 当前已验证的 `sType` 规则: - `sType = 1`:当前财务 API 使用的业务单据关联流水,样本中覆盖 `XS...` 与 `XT...` - `sType = 0`:当前样本对应 `SK...` 型独立收款流水;当前 `receipt` 查询会纳入它,`refund` 不会 示例: ```http GET /api/v1/finance/by-customer?customer_name_b64=6bi_54OI5pyN6aWw&record_types=sale,receipt,refund&include_cash_movement=true&include_adjustments=false Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "mode": "customer_finance", "customer_name": "鸿烨服饰", "customer_ids": [ "KH00999" ], "record_types": [ "sale", "receipt", "refund" ], "include_cash_movement": true, "include_adjustments": false, "status": "active", "snapshot_at": "2026-05-10T21:30:00Z", "total_count": 3, "sales_count": 1, "sale_returns_count": 0, "receipts_count": 1, "refunds_count": 1, "sales": [ { "BianHaoID": "XS20366749", "DanType": "成品销售单", "KhID": "KH00999" } ], "sale_returns": [], "receipts": [ { "BianHaoID": "XS20215718", "FkJinE": "378.00", "JieSunFS": "微信" } ], "refunds": [ { "BianHaoID": "XT20200743", "YfJinE": "-2201.00", "FkJinE": "0.00", "JieSunFS": "微信" } ] } ``` 未命中响应示例: ```json { "customer_name": "鸿烨服饰", "status": "not_found", "message": "未找到该 customer_name 对应的财务记录" } ``` 参数错误示例: ```json { "error": "record_types contains unsupported value" } ``` ## 6. Database Inspect Permission Check `GET /api/v1/db/permissions` 用途: - 检查当前数据库账号是否具备数据库分析所需的基础能力 - 尝试验证数据库连接、获取当前库名、列出可见表、读取字段元数据、读取 `sys` 元数据、检查 `VIEW DEFINITION`、以及对所有可见表执行 `SELECT TOP (1)` - 返回总体是否可用,以及各项检查结果 配置开关: ```yaml db_inspect: enabled: true ``` 成功响应示例: ```json { "can_inspect": true, "database_name": "RCYH2020", "visible_table_count": 32, "checks": [ { "name": "database_connection", "ok": true }, { "name": "list_base_tables", "ok": true }, { "name": "read_all_visible_table_columns", "ok": true }, { "name": "select_top_1_from_all_visible_tables", "ok": true } ] } ``` 字段说明: - `can_inspect`: 是否满足数据库分析所需的整体权限和可读能力 - `database_name`: 当前连接到的数据库名 - `visible_table_count`: 当前账号可见的基础表数量 - `checks`: 分项检查结果 - `failed_column_tables`: 无法读取字段元数据的表清单,仅检查失败时出现 - `failed_select_tables`: 无法执行 `SELECT TOP (1)` 的表清单,仅检查失败时出现 ## 7. List Database Tables `GET /api/v1/db/tables` 用途: - 返回当前数据库中当前账号可见的所有基础表 成功响应示例: ```json { "count": 2, "tables": [ { "schema": "dbo", "name": "D_KhDhd", "full_name": "dbo.D_KhDhd" }, { "schema": "dbo", "name": "B_Khzl", "full_name": "dbo.B_Khzl" } ] } ``` ## 8. List Table Columns `GET /api/v1/db/columns` 参数: - `table`: 必填,表名,格式为 `schema.table` 或 `db.schema.table` 用途: - 返回指定表的字段列表 - 返回字段名、类型、是否可空、长度、精度、顺序等信息 示例: ```http GET /api/v1/db/columns?table=dbo.D_KhDhd Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "table": "dbo.D_KhDhd", "count": 2, "columns": [ { "name": "ID", "data_type": "int", "nullable": false, "ordinal_position": 1 }, { "name": "BianHaoID", "data_type": "nvarchar", "nullable": true, "max_length": 50, "ordinal_position": 2 } ] } ``` ## 9. Generic Table Select `GET /api/v1/db/select` 参数: - `table`: 必填,表名,格式为 `schema.table` 或 `db.schema.table` - `columns`: 必填,逗号分隔的字段名列表,例如 `ID,BianHaoID` - `where`: 可选,受限条件表达式;支持 `=` `!=` `<>` `>` `>=` `<` `<=` `LIKE` `IS NULL` `IS NOT NULL`,多个条件只支持用 `AND` 连接;字符串字面量必须写成单引号,例如 `DanType = '客户退货单'` - `limit`: 可选,正整数;不传时使用默认值,并受服务端上限限制 用途: - 对指定表执行通用只读查询 - 仅返回请求中指定的字段集合 - 当前实现固定为 `SELECT TOP (limit)`,支持受限 `WHERE`,不支持自定义 SQL 示例: ```http GET /api/v1/db/select?table=dbo.D_KhDhd&columns=ID,BianHaoID&limit=10 Authorization: your-fixed-authorization-secret ``` ```http GET /api/v1/db/select?table=dbo.I_Sale&columns=BianHaoID,DanType,ShuLiang&where=DanType%20%3D%20%27%E5%AE%A2%E6%88%B7%E9%80%80%E8%B4%A7%E5%8D%95%27%20AND%20ShuLiang%20%3C%200&limit=10 Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "table": "dbo.D_KhDhd", "columns": [ "ID", "BianHaoID" ], "count": 2, "rows": [ { "ID": 1001, "BianHaoID": "KD20432358" }, { "ID": 1002, "BianHaoID": "KD20432359" } ] } ``` 参数错误示例: ```json { "error": "where is invalid" } ``` 当配置关闭时: ```json { "error": "db inspect api is disabled" } ``` ## 10. Get Current Cursor `GET /api/v1/cursor` 用途: - 查看当前游标值 - 查看最近一次人工修改游标前的 `origin_cursor` 示例: ```http GET /api/v1/cursor Authorization: your-fixed-authorization-secret ``` 成功响应示例: ```json { "cursor": 1500, "origin_cursor": 1250 } ``` ## 11. Set Cursor `POST /api/v1/cursor/set` 用途: - 人工把游标改到指定值 - 每次手工修改时,都会把修改前的游标保存到 `origin_cursor` 请求体: ```json { "value": 1500 } ``` 规则: - `value` 必须是非负整数 - 调用成功后: - `cursor` 更新为 `value` - `origin_cursor` 保存修改前的 `cursor` 请求示例: ```http POST /api/v1/cursor/set Authorization: your-fixed-authorization-secret Content-Type: application/json { "value": 1500 } ``` 成功响应示例: ```json { "cursor_before": 1250, "cursor_after": 1500, "origin_cursor": 1250, "updated": true } ``` ## 12. Get Image `GET /api/v1/image` 用途: - 根据给定文件名,从配置的图片目录读取对应文件 - 找到后返回图片内容的 Base64 字符串 - 找不到时返回 `404` 配置文件: ```yaml image: directory: "./images" ``` 参数: - `name`: 可选,原始文件名,必须是纯文件名,不能包含路径 - `name_b64`: 可选,文件名的 Base64URL 编码;当文件名包含 `#` 等 URL 特殊字符时推荐使用 - 如果 `name` 不带后缀,服务端会按 `.jpg`、`.png` 的顺序自动尝试 说明: - `name` 和 `name_b64` 二选一即可 - 如果文件名里包含 `#`,很多客户端会在真正发请求前把它后面的内容当作 URL fragment 截掉,因此推荐使用 `name_b64` 示例: ```http GET /api/v1/image?name=test Authorization: your-fixed-authorization-secret ``` ```http GET /api/v1/image?name_b64=YWJjIzEyMw Authorization: your-fixed-authorization-secret ``` 上面的 `name_b64=YWJjIzEyMw` 对应原始文件名: ```text abc#123 ``` 成功响应示例: ```json { "name": "test.jpg", "content_type": "image/jpeg", "data": "/9j/4AAQSkZJRgABAQ..." } ``` 错误响应示例: ```json { "error": "image not found" } ``` 说明: - `data` 是图片二进制内容的 Base64 编码 - `content_type` 会优先根据文件扩展名推断,推断不出来时会回退到内容检测 - 如果 `name` 没有后缀,会优先查找 `name.jpg`,找不到再查 `name.png` - 如果文件名中含有 `#`、空格等特殊字符,优先使用 `name_b64` - 为了安全,`name` 不能带目录分隔符,也不能包含 `..` ## 13. Cursor State File 默认文件: ```text ./data/cursor-state.json ``` 文件内容示例: ```json { "cursor": 1500, "origin_cursor": 1250 } ``` 说明: - `cursor`: 当前增量同步游标 - `origin_cursor`: 最近一次人工修改游标前的值