统一下载网关技术方案

1. 文档信息

  • 文档名称:统一下载网关技术方案
  • 文档类型:正式技术方案
  • 适用范围:cmclink-ibs-web-1 前端及对应后端下载服务
  • 当前状态:Draft
  • 目标读者:前端开发、后端开发、架构评审、测试、运维

2. 背景与问题

当前系统内存在多种文件下载来源,主要包括以下几类:

  1. 第三方平台下载链接
  2. 内部 COS 平台下载链接
  3. 业务系统动态生成文件流
  4. 后续可能扩展的新下载来源

现状中,不同来源的下载能力不一致,前端下载链路逐步暴露出以下问题:

2.1 来源能力不一致

  • 第三方链接通常不开放跨域,浏览器端无法稳定 fetch 文件内容。
  • 内部 COS 若支持 CORS,则前端可以 fetch -> blob -> download,但实现与第三方完全不同。
  • 新来源接入时,前端往往需要继续新增条件分支,导致下载逻辑扩散。

2.2 文件名不可控

  • 对于第三方跨域链接,前端无法稳定自定义下载文件名。
  • 浏览器对跨域资源的 download 属性支持有限,很多情况下会优先采用服务端响应头或 URL 中原始文件名。
  • 不同页面重复拼装文件名,存在维护成本和规则不一致问题。

2.3 安全与治理能力不足

  • 前端直接暴露真实第三方 URL、签名参数、桶名、路径结构。
  • 不利于统一鉴权、审计、失败追踪和访问控制。
  • 一旦上游下载规则变化,多个页面可能同时受影响。

2.4 前端复杂度持续上升

  • 页面层和业务 composable 容易出现大量下载分支逻辑。
  • 公共下载能力需要兼容越来越多来源类型,职责边界不清晰。
  • 下载失败原因难以定位,测试成本较高。

3. 方案目标

本方案旨在通过"后端统一下载网关"解决多来源下载问题,目标如下:

  1. 为前端提供统一、稳定、可扩展的下载协议。
  2. 将跨域、来源识别、鉴权、文件名控制等复杂性收敛到后端。
  3. 统一下载文件名、响应头、错误码、审计日志和监控指标。
  4. 支持未来新增下载来源时按适配器方式扩展,不影响前端主流程。
  5. 保持前端业务页面调用方式简洁,避免继续扩散来源差异逻辑。

4. 适用范围与非目标

4.1 适用范围

  • 保函下载
  • 发票下载
  • 舱单下载
  • 提单及其他导出文件下载
  • 内部 COS / 第三方平台 / 动态生成文件流等多来源文件场景

4.2 非目标

  • 本方案不覆盖文件上传能力治理。
  • 本方案不强制所有历史接口一次性切换,允许分阶段迁移。
  • 本方案不强制引入断点续传;如后续存在大文件诉求,可作为增强项单独评估。

5. 关键结论

5.1 结论

推荐采用"后端统一抹平下载来源差异,前端统一消费二进制流"的架构方案。

5.2 原因

  • 浏览器跨域限制只作用于前端页面脚本,不适用于服务端到服务端调用。
  • 后端更适合承接第三方下载鉴权、地址适配、签名保护和文件名统一控制。
  • 前端只需处理统一 blob 下载或标准流下载,逻辑更稳定、可维护性更强。

6. 总体方案

6.1 总体思路

前端不再直接面向第三方下载 URL 作为主链路,而是统一调用平台后端提供的下载接口。后端根据文件来源选择对应适配器,从上游获取文件流并流式转发给前端,同时统一设置响应头。

6.2 架构图

text 复制代码
前端业务页面 / Composable
        |
        v
统一下载调用层(useFileDownload / API)
        |
        v
后端统一下载网关
        |
        +-------------------+
        |                   |
        v                   v
第三方平台适配器       内部 COS 适配器
        |                   |
        +---------+---------+
                  |
                  v
             上游文件来源

6.3 角色分工

  • 前端:发起统一下载请求、展示 loading、消费 blob、处理用户提示。
  • 后端下载网关:统一鉴权、来源识别、文件名生成、流式转发、错误映射、日志记录。
  • 来源适配器:屏蔽不同上游文件来源的调用差异。

7. 技术选型与设计原则

7.1 设计原则

  • 单一入口:前端只认统一下载协议。
  • 后端抹平:来源差异由服务端处理。
  • 流式转发:避免大文件整包落内存。
  • 文件名统一:优先由后端通过响应头控制。
  • 兼容渐进迁移:允许保留历史直链下载能力作为临时兜底。

7.2 推荐技术路径

  • 前端:继续使用统一下载 Hook,例如 useFileDownload
  • 后端:新增统一下载网关接口
  • 网关实现:基于流式响应透传上游文件
  • 来源扩展:采用适配器模式实现来源隔离

8. 详细设计

8.1 前端调用模型

前端统一通过平台 API 下载文件,不再直接使用第三方 URL 作为主下载方式。

推荐调用方式如下:

ts 复制代码
await download(async () => api.downloadIndemnityFile({
  bizId: '123',
  bizType: 'indemnity',
}), {
  fileName: 'GUARANTEE_LETTER_BL001.pdf',
  fileType: 'pdf',
})

前端职责收敛为:

  • 调用统一下载 API
  • 展示下载中的 loading
  • 解析 blob 或响应头中的文件名
  • 统一错误提示

前端不再负责:

  • 判断第三方链接是否可跨域
  • 判断当前来源类型
  • 决定是否走 fetch + blob 或直链下载
  • 拼接第三方签名 URL

8.2 后端统一下载接口设计

统一下载接口建议支持两种形式,项目可按业务现状择一或并行使用。

方案 A:按资源 ID 下载

http 复制代码
GET /api/file-center/download/{resourceId}

适用于平台已经具备统一文件资源模型的场景。

方案 B:按业务语义下载

http 复制代码
POST /api/export/download
Content-Type: application/json

请求示例:

json 复制代码
{
  "bizType": "indemnity",
  "bizId": "123",
  "templateType": "guaranteeLetter",
  "expectedFileName": "GUARANTEE_LETTER_BL001.pdf"
}

适用于导出即下载、按业务上下文动态获取文件的场景。

8.3 后端请求模型建议

ts 复制代码
interface DownloadRequest {
  bizType: string
  bizId: string
  templateType?: string
  expectedFileName?: string
  locale?: string
}

8.4 后端响应规范

成功时直接返回二进制流,推荐响应头如下:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename*=UTF-8''GUARANTEE_LETTER_BL001.pdf
Content-Length: 245678
Cache-Control: private, no-store
X-Download-Source: third-party

失败时返回统一 JSON 错误体:

json 复制代码
{
  "code": "DOWNLOAD_UPSTREAM_TIMEOUT",
  "message": "文件下载失败,请稍后重试",
  "traceId": "xxx"
}

8.5 下载网关内部流程

统一下载网关建议按以下顺序处理:

  1. 校验登录态与业务权限
  2. 根据业务参数定位文件来源
  3. 选择适配器获取上游文件流
  4. 生成或覆盖最终下载文件名
  5. 设置标准响应头
  6. 以流式方式回传前端
  7. 记录审计日志、耗时、结果码与 traceId

8.6 来源适配器设计

建议在后端引入来源适配器层。

接口示例如下:

ts 复制代码
interface DownloadAdapter {
  canHandle(sourceType: string): boolean
  getFileStream(input: DownloadRequest): Promise<{
    stream: NodeJS.ReadableStream
    fileName?: string
    contentType?: string
    contentLength?: number
  }>
}

推荐适配器划分:

  • ThirdPartyDownloadAdapter
  • InternalCosDownloadAdapter
  • GeneratedFileAdapter
  • LegacyUrlAdapter

8.7 文件名规则

文件名控制推荐以下优先级:

  1. 业务明确传入的标准文件名
  2. 后端按业务规则动态生成文件名
  3. 上游响应头中的文件名
  4. 系统兜底文件名

推荐统一使用 UTF-8 编码的 filename* 响应头,避免中文文件名乱码。

8.8 前端统一下载能力定位

前端仍保留统一下载 Hook,但职责调整为"消费层"而非"来源治理层"。

保留职责:

  • loading 管理
  • blob 下载触发
  • 响应头解析文件名
  • 通用异常提示

弱化职责:

  • 来源识别
  • 跨域能力判断
  • 第三方链接命名控制

9. 安全设计

9.1 安全收益

  • 隐藏第三方真实下载地址、签名参数和存储桶信息
  • 下载前统一执行权限校验
  • 便于增加下载频控、黑白名单、操作审计
  • 降低前端直接暴露外部存储结构的风险

9.2 安全要求

  • 后端下载接口必须校验登录态和业务权限
  • 禁止通过简单拼接 URL 直接访问任意外部文件
  • 记录下载行为审计日志,包括用户、时间、业务主键、来源、结果、traceId
  • 对敏感文件下载场景支持额外鉴权或审批

10. 性能与稳定性设计

10.1 推荐实现方式

  • 使用流式透传,不将整文件一次性加载到内存
  • 透传或补充 Content-Length
  • 根据来源设置合理超时与重试策略
  • 支持连接中断时及时释放上游请求

10.2 关注点

  • 大文件下载会提升后端带宽与连接压力
  • 第三方平台可能存在超时、限流或证书问题
  • 统一下载网关应纳入监控治理范围

10.3 推荐监控指标

  • 下载成功率
  • 下载平均耗时
  • 各来源失败率
  • 平均文件大小
  • 网关并发数
  • 上游超时次数

11. 错误码建议

建议为下载网关定义统一错误码:

错误码 含义 说明
DOWNLOAD_UNAUTHORIZED 未授权下载 登录失效或无权限
DOWNLOAD_NOT_FOUND 文件不存在 业务记录不存在或上游文件不存在
DOWNLOAD_UPSTREAM_TIMEOUT 上游超时 第三方或 COS 响应超时
DOWNLOAD_UPSTREAM_FORBIDDEN 上游拒绝访问 上游鉴权失败
DOWNLOAD_SOURCE_UNSUPPORTED 不支持的来源 未匹配到适配器
DOWNLOAD_INTERNAL_ERROR 内部异常 网关内部错误

12. 兼容与迁移方案

12.1 迁移原则

  • 新增业务优先接入统一下载网关
  • 存量业务逐步迁移,不要求一次性替换全部直链下载
  • 前端统一下载 Hook 尽量保持 API 不变,降低改造面

12.2 分阶段迁移

Phase 1:保函试点

  • 后端为保函场景新增统一下载接口
  • 前端 useIndemnityGenerate 改为调用后端统一下载接口
  • 保留原 downloadUrl 模式作为短期回退方案

Phase 2:通用下载网关沉淀

  • 将发票、舱单、提单等相似下载场景迁入统一网关
  • 沉淀标准错误码、日志字段和响应头规范

Phase 3:下线历史直链主链路

  • 新增需求不再允许页面直接消费第三方下载 URL
  • 历史页面逐步移除来源判断逻辑
  • 统一收敛到后端 blob/流下载模式

12.3 前端改造建议

  • 页面层不再直接处理第三方 URL
  • 业务 composable 不再判断来源类型
  • useFileDownload 只保留统一消费能力

13. 风险与对策

风险 描述 对策
后端带宽压力上升 下载链路集中到网关 流式转发、网关限流、监控扩容
第三方不稳定 上游超时、限流、证书问题 超时控制、重试、熔断、降级提示
大文件内存占用 错误实现可能整包读入内存 强制流式透传
文件名乱码 中文文件名或特殊字符处理不一致 统一 filename* UTF-8 编码
历史改造成本 存量页面较多 分阶段迁移、优先试点

14. 验收标准

统一下载网关方案上线后,应至少满足以下验收标准:

  1. 前端新增下载场景无需识别具体来源类型。
  2. 第三方不可跨域来源可通过统一下载接口正常下载。
  3. 中文和英文文件名均可稳定下载且不乱码。
  4. 后端可记录完整下载日志并支持 traceId 排查。
  5. 保函场景完成试点迁移且无业务回退事故。
  6. 网关具备基础监控能力,可统计成功率和失败原因。

15. 推荐实施结论

对于当前"第三方不可跨域、内部 COS、未来多来源扩展"的下载场景,推荐采用"后端统一下载网关 + 前端统一消费二进制流"的方案。

该方案具备以下长期价值:

  • 前端调用方式稳定
  • 文件名控制能力稳定
  • 来源扩展成本低
  • 安全治理能力强
  • 日志与异常排查更清晰

从项目演进角度看,该方案是当前下载能力治理中最优先、最具长期收益的基础设施改造方向。

16. 附录

16.1 前端调用示例

ts 复制代码
async function handleDownload() {
  await download(async () => api.downloadIndemnityFile({
    bizType: 'indemnity',
    bizId: '123',
  }), {
    fileName: 'GUARANTEE_LETTER_BL001.pdf',
    fileType: 'pdf',
  })
}

16.2 后端返回示例

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename*=UTF-8''GUARANTEE_LETTER_BL001.pdf
相关推荐
Java识堂1 小时前
注册中心选型
架构
王二端茶倒水1 小时前
智慧酒店 WiFi 运营:从 Portal 认证到住客体验闭环
运维·物联网·架构
三块可乐两块冰1 小时前
rag学习5
linux·前端·python
淡海水1 小时前
38-Hybrid生态-LeanCLR总览
unity·架构·c#·热更新·clr·hybrid·leanclr
铁皮饭盒1 小时前
Bun + SQLite 10个实用技巧
前端·javascript·后端
Hooray1 小时前
告别低效循环!AI Agent 编排+编程显示器,让前端开发效率实现断代式跃升
前端·人工智能·ai编程
程序猿阿伟1 小时前
《拆解Chrome存储架构:浏览痕迹的残留死角与清除路径》
jvm·chrome·架构
飞天狗1112 小时前
零基础JavaWeb入门——第4课:表单处理 —— 浏览器怎么把数据发给服务器
java·开发语言·前端·后端·servlet
Hooray2 小时前
前端暗黑模式的适配艺术
前端·vue.js·视觉设计