
很多 SaaS 产品都会遇到文件上传:头像、图片、PDF、合同、附件、数据表、音频、视频、导入文件。
文件上传看起来只是一个表单功能,但真正上线后会牵扯很多问题:文件大小、格式校验、存储路径、权限控制、安全扫描、上传进度、失败重试、CDN、删除策略和成本。
如果一开始设计太随意,后面文件一多,系统会很难维护。
新手最容易犯的错误,是把文件内容直接存进数据库。
数据库适合存结构化数据,比如用户、订单、项目、文件记录;不适合存大量二进制文件。文件本身应该放到对象存储里,比如 S3、R2、OSS、COS、GCS 等。
数据库里只保存文件元数据:
file_id
owner_id
bucket
object_key
file_name
mime_type
size
status
created_at
这样数据库负责“文件是谁的、在哪里、是什么状态”,对象存储负责保存真正的文件内容。
文件在对象存储里的路径要设计清楚。
不要使用用户原始文件名作为唯一路径,也不要把敏感业务信息直接写进路径。原始文件名可能重复,可能包含特殊字符,也可能暴露隐私。
更推荐使用系统生成的 key:
uploads/{user_id}/{file_id}/{safe_file_name}
或者:
uploads/{yyyy}/{mm}/{file_id}
文件展示时可以保留原始文件名,但存储路径应该由系统控制。
早期很多人会让文件先上传到自己的业务服务器,再由服务器转存到对象存储。
这种方式简单,但大文件一多,业务服务器会承受大量带宽和内存压力。更好的方式是预签名上传。
流程是:
1. 前端请求后端创建上传凭证
2. 后端校验用户权限和文件信息
3. 后端生成预签名 URL
4. 前端直接上传到对象存储
5. 上传完成后通知后端确认
6. 后端更新文件状态
这样文件数据不需要经过你的业务服务器,系统更稳,也更省资源。
不要相信前端传来的文件。
上传前后都要做校验:文件大小、扩展名、MIME 类型、业务限制、用户剩余额度、上传次数、文件数量。
前端校验用于减少用户等待,后端校验用于保护系统。对象存储上传策略也可以限制文件大小和类型。
例如:
头像:只允许 jpg/png/webp,最大 5MB
PDF:只允许 application/pdf,最大 20MB
导入表格:只允许 csv/xlsx,最大 10MB
视频:限制格式、大小和时长
校验规则越清楚,后面越少脏数据。
文件上传成功,只代表文件到了存储系统,不代表它已经可以使用。
很多文件还需要后续处理:图片压缩、缩略图生成、病毒扫描、PDF 解析、音视频转码、表格解析、内容安全检测。
因此文件表里应该有状态字段:
pending_upload
uploaded
processing
ready
failed
deleted
用户上传完成后,可以先显示“处理中”,等后台任务处理完再变成可用。
文件权限不能只靠 URL 隐藏。
如果是私有文件,用户访问时应该先经过你的业务系统校验权限,再生成临时访问 URL,或者通过受控下载接口返回。
常见权限问题包括:
用户 A 访问用户 B 的文件
团队成员访问已删除项目文件
公开分享链接泄露私密文件
离职成员仍能访问旧文件
临时 URL 有效期太长
文件通常包含隐私和业务数据,权限设计要比普通页面更谨慎。
不是所有文件都需要私有。
比如公开头像、公开封面图、文章配图,可以放在公共 bucket 或走 CDN。合同、发票、导入数据、用户附件、内部文档,应该放在私有 bucket。
公共文件追求访问速度和缓存,私有文件追求权限安全和可审计。
不要把所有文件都混在一个权限模型里。
文件上传和普通表单不同,用户会等待。
如果上传大文件时没有进度条、没有取消按钮、没有失败提示,用户会不知道系统是否卡住。
至少要提供:
上传进度
上传中状态
失败提示
重新上传
取消上传
大小限制提示
格式限制提示
文件上传体验越清楚,客服问题越少。
用户删除文件时,是否立刻从对象存储删除?
这要看业务。很多系统会先软删除数据库记录,再异步清理对象存储。这样可以避免误删,也能给恢复和审计留空间。
你需要考虑:
用户删除后是否可恢复
文件是否被多个业务对象引用
对象存储是否有生命周期策略
是否需要定期清理孤儿文件
是否需要保留审计记录
文件删除不是简单的 delete,尤其在团队协作和付费业务里。
文件系统的成本不只包括存储。
还包括上传流量、下载流量、CDN 流量、图片处理、视频转码、请求次数、备份、跨区域复制。
如果你的产品允许用户上传大文件或视频,成本可能很快上升。早期就要设置大小限制、配额和清理策略。
不要等账单异常后才想起限制上传。
可以按下面结构设计:
前端:
选择文件 / 校验 / 进度 / 重试
后端:
权限校验 / 创建文件记录 / 生成预签名 URL / 确认上传
对象存储:
保存原始文件 / 权限控制 / 生命周期
后台任务:
扫描 / 压缩 / 解析 / 转码 / 生成缩略图
数据库:
文件元数据 / 状态 / 所属用户 / 权限 / 业务关联
这比“一个上传接口”更接近真实系统。
文件上传系统的关键,不是把文件传上去,而是让文件从上传、存储、处理、访问、删除到审计都有清晰规则。
早期最推荐的结构是:对象存储保存文件,数据库保存元数据,预签名 URL 直接上传,后台任务异步处理,权限访问单独控制。
下一篇,我们继续聊存储选择:图片存储怎么选。