3. 导出请求链路(一):请求接收与参数校验——RESTful API 设计、参数模型与异步/同步模式选择

报表导出请求的入口是整个链路的“守门员”。一个设计良好的请求接收层,能够在流量进入核心处理逻辑之前,完成格式校验、语义校验与模式决策,从而避免无效请求消耗后端资源。本节聚焦于 RESTful API 端点设计、参数模型定义以及同步/异步模式的选择策略。

3.1 RESTful API 端点设计

报表导出通常设计为 POST 请求,因为请求体包含复杂的过滤条件与配置参数,且操作具有副作用(创建导出任务或生成文件)。

端点路径 请求方法 适用场景 说明
/api/v1/reports/export POST 同步导出(小数据量) 直接返回文件流或 Base64 编码内容
/api/v1/reports/export/async POST 异步导出(大数据量) 返回任务 ID,客户端轮询或回调获取结果
/api/v1/reports/export/tasks/{taskId} GET 异步任务状态查询 返回任务进度、状态、下载链接
设计原则:端点路径应包含版本号(v1),避免未来接口变更时破坏现有客户端。建议将同步与异步端点分离,而非通过单个参数控制,以提升 API 的可读性与路由匹配效率。

3.2 参数模型定义

导出请求的参数模型需要兼顾灵活性与校验严格性。以下是一个典型的 JSON 请求体结构:

{
  "reportCode": "SALES_DAILY",        // 必填,报表模板编码
  "format": "xlsx",                   // 必填,导出格式:xlsx | csv | pdf
  "fields": ["date", "revenue", "region"], // 可选,指定导出字段,为空则导出全部字段
  "filters": {                        // 可选,过滤条件
    "dateRange": {
      "start": "2025-01-01",
      "end": "2025-01-31"
    },
    "region": ["华东", "华南"],
    "productCategory": "电子产品"
  },
  "sort": {                           // 可选,排序规则
    "field": "revenue",
    "order": "desc"
  },
  "pageSize": 10000,                  // 可选,每页记录数,默认 5000
  "maxRows": 500000,                  // 可选,最大导出行数,默认 100000
  "async": true                       // 可选,是否异步,默认 false
}

3.3 参数校验清单

后端必须在反序列化后立即执行分层校验,避免脏数据进入导出引擎。

  • 格式校验:reportCode 是否存在于报表注册表中;format 是否在允许列表(xlsx, csv, pdf)内。
  • 字段校验:fields 数组中的每个字段名是否属于该报表模板的合法字段集合;若传入非法字段,直接拒绝请求。
  • 过滤条件校验:日期范围 start 不能晚于 end;枚举型过滤值(如 region)必须在预定义枚举列表中。
  • 边界校验:pageSize 不得超过系统上限(如 50000);maxRows 不得超过单次导出配额(如 100 万行)。
  • 权限校验:当前用户是否拥有该报表的导出权限;过滤条件中的维度是否在用户数据权限范围内。
常见陷阱:仅依赖前端校验,忽略后端重复校验。攻击者可以绕过前端直接调用 API,因此后端必须对所有参数进行独立、完整的校验,尤其是过滤条件中的 SQL 注入风险字段。

3.4 同步 vs 异步模式选择

模式选择直接影响用户体验与系统资源分配。下表对比了两种模式的核心差异:

维度 同步模式 异步模式
响应时间 毫秒~秒级(受数据量影响) 立即返回任务 ID,实际耗时分钟级
适用数据量 < 10 万行 > 10 万行 或 复杂报表
连接占用 长连接,占用 HTTP 线程 短连接,释放线程资源
错误处理 直接返回 HTTP 4xx/5xx 通过任务状态接口查询错误信息
重试机制 客户端需重新发起请求 服务端可自动重试失败任务
推荐策略:在网关层或业务层根据 maxRows 自动切换模式。当请求的预估行数低于阈值(如 5 万行)时走同步路径,否则自动转为异步。同时允许客户端通过 async 参数强制指定模式。

3.5 请求接收与校验流程(SVG)

下图展示了从请求到达至进入导出引擎前的完整校验链路:

请求接收与参数校验流程 HTTP POST 请求 JSON 反序列化 格式校验 字段 & 过滤校验 权限校验 同步/异步模式决策 同步导出引擎 异步任务队列 校验失败 直接返回 4xx 错误

3.6 异步模式下的任务模型

当请求被判定为异步模式时,系统会立即创建一个导出任务并返回任务 ID。任务模型的核心字段如下:

字段 类型 说明
taskId UUID 全局唯一任务标识
status 枚举 PENDING / RUNNING / SUCCESS / FAILED
progress Integer 0~100 的进度百分比
downloadUrl String 导出完成后的文件下载链接(临时签名 URL)
errorMessage String 失败时的详细错误信息
createdAt DateTime 任务创建时间
最佳实践:任务状态应存储在 Redis 或数据库中以支持持久化查询。下载链接建议使用对象存储的预签名 URL,并设置过期时间(如 30 分钟),避免文件长期暴露。

3.7 参数校验失败响应规范

统一的错误响应格式有助于客户端快速定位问题。推荐使用以下结构:

{
  "code": 40001,
  "message": "参数校验失败",
  "details": [
    {
      "field": "filters.dateRange.start",
      "message": "开始日期不能晚于结束日期"
    },
    {
      "field": "fields[2]",
      "message": "字段 'profit' 不在报表模板 'SALES_DAILY' 的合法字段列表中"
    }
  ]
}

通过 details 数组逐条列出所有校验失败项,避免客户端因第一个错误修复后再次请求时遇到第二个错误。