做业务系统时,文件上传看起来是个小功能,真正接上线才发现不少坑。图片、视频、安装包动辄几百兆,如果每个文件都要先经过自己的应用服务器中转,带宽和存储压力很快就会显现。阿里云对象存储 OSS 提供了比较成熟的阿里云文件上传方案,能把大部分流量交给云端。下面结合一个实际案例,说说几种上传方式各自适合什么场景,以及选型时该看哪些条件。

先定好文件的走向
上传链路大体有两种。一种是客户端把文件发给应用服务器,服务器再转存到 OSS。这种写法最直观,接口好写,调试也方便,但文件实际上要经过服务器两次,上行一次、转存一次,带宽占用基本翻倍。文件量小的时候感觉不到,高峰期就容易拖慢订单、登录这类普通接口。另一种是客户端直接把文件传到 OSS,应用服务器只负责签发授权。绝大多数业务场景都应该走这条路,也就是常说的直传。
所以选型的第一个问题是文件要不要经过你的服务器,具体用哪个 API 反而排在后面。这一点想清楚,后面的方式基本就有了方向。
几种常用的上传方式
- 简单上传(PutObject):一次请求传一个文件,单文件最大 5GB。头像、普通图片、文档这类文件用它就够了,代码最少,出错面也最小。
- 分片上传(Multipart Upload):把大文件切成若干分片,并行上传,全部完成后再合并。分片数量上限为 10000。视频和安装包基本都应该走这里,单次请求太大,网络一抖就得整个重来。
- 表单上传(PostObject):浏览器通过 HTML 表单或 POST 请求直接提交到 OSS,靠策略和签名完成授权。纯 Web 端的上传页面用它最省事,不需要在前端引入太多 SDK。
- STS 临时授权:由 RAM 服务签发有时效的临时凭证,客户端拿到后直接调用 SDK 上传。移动端和需要灵活控制的复杂场景常用它,好处是不用把长期 AccessKey 放进前端。
这四种方式不互斥。一个系统里常见的组合是小文件用简单上传,大文件用分片,Web 页面用表单直传,App 则用 STS。先按文件大小和端的类型分开,比硬选一个再到处打补丁要顺手得多。
案例:电商商品素材上传
某电商团队需要让运营同学上传商品主图和短视频。最初的做法是后端接收文件,再转存到 OSS。平时没问题,每逢大促,视频上传请求把应用服务器的带宽占满,订单接口的响应时间从几十毫秒涨到了秒级。订单代码本身没有问题,问题是文件流量和业务流量挤在同一条带宽上。
调整后的方案分三步走。运营登录后台后,前端请求应用服务器的一个签发接口,服务器先校验用户权限,再返回一份带有效期的上传策略和签名。前端拿到签名,用 OSS SDK 把文件直接传到指定 Bucket。上传完成后,OSS 通过回调通知业务服务器,业务服务器只需要记录文件地址和元数据,不再碰文件内容。
改造之后,应用服务器不再处理文件流量,大促期间订单接口恢复稳定。运营上传大视频时,分片上传加断点续传也派上了用场。网络抖动只需重传失败的分片,已成功的部分保留下来,不用从头再来。
服务端签名直传要守住几个口子
直传省了服务器的带宽,但权限边界要交给签名策略来守。下面三点是实际做的时候最容易忽略的。
策略要收紧,越具体越安全
上传策略里至少要限定文件大小范围、允许的文件类型、目标目录前缀和过期时间。比如只允许 image/ 目录下的 jpg 和 png,单文件不超过 10MB,有效期设为几分钟。策略写得宽松,签名一旦泄露或被人拿去反复调用,损失就会很大。过期时间尤其别图省事设成几天。
目录按业务和用户隔离
object key 里建议带上业务前缀和租户或用户标识,例如 products/{tenantId}/{date}/。这样权限控制可以直接按前缀划分,后面做生命周期管理、成本统计、排查问题时也能快速定位文件属于谁。目录一开始不规划,后面迁移的代价通常比想象中大。
回调要做幂等
网络环境下,同一个回调可能重复到达,这很正常。业务侧应该用文件地址或唯一标识作为幂等键,写库前先判断是否已存在。否则一个文件可能在数据库里出现两条记录,后面的统计和展示都会跟着出错。
大文件分片上传怎么落地
分片上传的基本流程是:初始化任务拿到 UploadId,逐个上传分片并记录每个分片返回的 ETag,最后调用合并接口完成上传。流程本身不复杂,细节上有几件事值得留意。
分片大小可以按文件总大小动态计算。常见做法是控制在几 MB 到几十 MB 之间,分片太小,请求数量多,管理成本上去;分片太大,单片失败后重传的代价又高。前端应该把已成功分片的编号和 ETag 存到本地,比如 localStorage 或 IndexedDB,断点续传时直接跳过它们。
还有一个容易被忘掉的地方。用户中途关掉页面、任务放弃,未合并的分片会一直留在 Bucket 里并计入存储。要么在业务上调用取消接口主动清理,要么配置生命周期规则兜底。否则过一段时间回头看账单,会发现有一批看不见的碎片在吃空间。
安全与成本的几条底线
- 不要把 AccessKey 写进前端代码或提交到代码仓库。用 RAM 子账号加 STS 临时凭证,泄露后的影响范围小得多。
- Bucket 默认保持私有读写。需要公开访问的内容,通过 CDN 或签名 URL 对外提供,不要为了省事直接开放公共读。
- 开启上传日志和访问监控。上传量突然暴涨、某个 IP 频繁请求签发接口,这类异常要能及时发现。
- 给临时文件和未完成的分片配置生命周期规则,让它们定期自动删除。
怎么选
阿里云文件上传没有统一答案,关键看文件大小和使用的端。小文件用简单上传,省心;大文件用分片上传,抗网络波动;Web 页面可以直接用表单直传;移动端或者需要更灵活的权限控制时,配合 STS 更合适。无论哪种,核心思路都是让文件尽量绕开应用服务器,同时用签名策略把权限边界守住。
如果你现在还在纠结,可以先从一个最具体的业务场景做起,比如商品图片上传,把签发、直传、回调这条链路跑通,再去补分片和生命周期这些细节。一次把所有情况都考虑进去的方案,往往落地最慢。