Skip to content

文件与媒体上传管线:直传 OSS、压缩与分片断点续传 ​

回到总览:后台 / API / 数据层
相关模块:大文件下载、断点续传与多线程分片下载架构 · 项目案例:download_service.dart 的下载 / 校验 / 原子更新 / 失败恢复

一句话定义 ​

文件与媒体上传管线是指在移动端处理图片、音视频等大文件上传时,通过客户端本地预压缩、获取服务端 OSS / COS 预签名凭证直传(Presigned URL) 以及大文件分片并发上传与断点续传,实现高可靠、低服务器带宽消耗的媒体传输架构。

代码索引 ​

计划补齐的实验:

  • labs/shared/backend-data/media-pipeline-demo/ — 图片/视频质量压缩、OSS 预签名直传与 MultipartUpload 模拟测试

为什么需要 ​

  • 为什么移动端上传图片或视频时,绝对不能将大文件字节流直接 MultipartPOST 提交给业务后台服务器?
    • 一句话答:业务后台服务器(如 Java / Node API)的带宽和 CPU 资源极其昂贵,处理海量大文件流会导致 API 服务器网关卡死;正确的架构是向后台申请对象存储(阿里云 OSS / 腾讯云 COS / AWS S3)的预签名直传 URL,由客户端直接将文件流上传到对象存储 CDN 节点。
  • 为什么 10 年 Android 工程师设计媒体上传管线时必须引入预压缩(Pre-compression)?
    • 一句话答:现代手机拍照单张图片高达 10MB~20MB,未压缩直接上传不仅消耗用户大量移动流量,且在弱网下极易失败;本地压缩(如将图片降至 1080P、80% 质量)可以将体积缩小 90% 以上,显著提升上传成功率。

底层机制 ​

1. OSS 预签名凭证直传流程 (Presigned URL Upload) ​

text
[客户端 (Android / Flutter)] ─── (1. POST /api/upload/credential) ───► [业务 API 服务器]
            │                                                              │
            │ ◄── (2. 返回预签名 URL: https://bucket.oss...&Signature=xxx) ──┘
            │
            └─── (3. PUT 预签名 URL 直接上传大文件二进制流) ─────────────► [阿里云 OSS / AWS S3]
                                                                           │
                                                                           ▼
[业务 API 服务器] ◄─── (4. OSS 成功回调 Webhook / 客户端确认) ──────────────┘
  1. 申请凭证:客户端携带文件名、MD5 向业务服务器发起申请。
  2. 生成签名:业务服务器使用 AccessKeySecret 生成带有有效期的预签名 URL(Presigned URL) 。
  3. 直传 OSS:客户端直接使用 HTTP PUT 将文件流上传到 OSS 节点,彻底不占用业务服务器带宽!

2. 大文件分片上传 (Multipart Upload) 与断点续传 ​

对于大于 20MB 的视频文件,采用分片上传:

text
大视频文件 (100MB)
  ├── Part 1 (10MB) ──► 线程 1 上传到 OSS ──► 获得 ETag 1
  ├── Part 2 (10MB) ──► 线程 2 上传到 OSS ──► 获得 ETag 2
  └── ...
                                               │
                                               ▼
[合并分片] ── CompleteMultipartUpload (带上所有 ETag) ──► 文件合成完成!

Android / Flutter / Web / Backend 对照 ​

环节Android 宿主Flutter (Dart)Web 前端
图片压缩Luban (鲁班压缩) / Native WebPflutter_image_compressCanvas 压缩 (toDataURL)
视频压缩MediaCodec / FFmpeg / LightCompressorvideo_compress 插件WebAssembly (FFmpeg.wasm)
直传引擎OkHttp / 阿里云 OSS Android SDKdio / OSS Dart SDKaxios / OSS JS SDK

常见场景 ​

1. 图片上传前动态压缩处理 (Luban 算法口径) ​

java
// 使用 Luban 算法根据原始宽高比例计算最优压缩分辨率
File compressedImageFile = Luban.with(context)
        .load(originalFile)
        .ignoreBy(100) // 100KB 以下不压缩
        .setTargetDir(getCacheDir().getPath())
        .get(originalFile.getAbsolutePath());

常见误配、事故后果与排障 ​

1. 事故:客户端在后台上传大视频时遭遇进程被杀,恢复后从头开始上传 ​

  • 误配原因:未将大视频切割为固定 Part(如 5MB 一个分片),没有在本地数据库记录已被 OSS 确认接收的 PartNumber 和 ETag。
  • 后果:90% 的上传进度因断网或后台被杀作废,重新上传消耗数几百兆用户流量。
  • 排障与修法:使用 OSS 分片上传 API (InitiateMultipartUpload + UploadPart);每成功上传一个 Part,在本地记录其 ETag,恢复上传时调用 ListParts 跳过已上传的分片。

与相近概念对比 ​

上传方式业务服务器带宽消耗是否支持分片断点续传适合场景
业务 API 中转极高否极小文件(如用户头像修改 50KB)
OSS 预签名直传零否普通图片、小音频直传
OSS 分片直传零是大视频、日志压缩包、大资源包

对应实验 ​

计划补齐的实验:

  • labs/shared/backend-data/media-pipeline-demo/ — 图片/视频质量压缩、OSS 预签名直传与 MultipartUpload 模拟测试

复习检查题 ​

  1. 为什么在上传大文件时,推荐使用“OSS 预签名直传(Presigned URL)”而不是将文件直接传给业务后台服务器?

    答:因为业务后台服务器的主要职责是处理轻量级的 JSON 业务逻辑,其网关和网络带宽资源极其昂贵。如果让大文件直接经过业务服务器中转,会瞬间吃满服务器的网络上行/下行带宽与 CPU,导致其他正常的 API 业务请求超时卡死。使用预签名直传,客户端直接将文件流上传给专业的海量带宽对象存储(OSS/S3)节点,彻底释放了业务服务器的压力。

  2. 在 OSS 分片上传(Multipart Upload)中,ETag 扮演了什么角色?

    答:ETag 是 OSS 服务端在成功接收并保存某个文件分片(Part)后返回给客户端的唯一哈希校验码。客户端在上传完所有分片后,需要调用 CompleteMultipartUpload 接口,将所有分片的 PartNumber 及其对应的 ETag 列表提交给 OSS;OSS 校验所有分片 ETag 无误后,才会将这些分片合并为一个完整的目标文件。

速记 ​

  • 直传原则:业务服务器发预签名 URL,客户端直接 PUT 上传 OSS。
  • 本地预压缩:图片用 Luban 算法压分辨率,视频降码率,节省 90% 流量。
  • 大文件分片:20MB+ 视频走 MultipartUpload,记录 ETag 实现断点续传。

站点构建时间:2026/8/24 23:43:17