boxmoe_header_banner_img

Hello! 欢迎来到我的博客!

加载中

文章导读

对象存储解决方案


avatar
xiaoifei 2026年6月13日 5

前言

本文为个人项目中使用云厂商对象存储技术方案的探究

为何使用对象存储

对象存储,可以理解成专门用来存文件的云端硬盘
使用对象存储无非解决下面几个痛点

  • 自建服务器存储管理成本高
  • 小厂使用应用上云,云服务器存储价格贵,使用oss解析存储
  • 为了更好结合云厂商的cdn,ecs服务
  • 开箱即用,减少开发运维成本

使用对象存储面临的问题

对于成熟的文件存储方案简单的“把文件上传到云,把文件从云下载”就完了,还要同时解决这些问题

  • 文件从哪里上传?
  • 谁有权限上传?
  • 上传后谁能访问?
  • 后端要不要经过文件内容?
  • 怎么防止用户乱传、盗传、越权传?
  • 图片、头像、课程视频、私密附件分别怎么处理?
  • 文件上传成功后,数据库怎么记录?
  • 文件删除、审核、转码、CDN 加速怎么接?

知识点

资源访问类型

资源可以分为公共资源私有资源
公共资源会公开给网络上所有人访问,例如一些图源站点使用oss.xxx.com/1.jpg,更换资源后缀就可以访问其他资源oss.xxx.com/1.jpg
这种方式无论是从安全性还是流量控制都不可控,所以用后端需要进行包装。例如使用xxx.com/getUrl请求后端,然后再返回图片,将资源的访问路径变成黑盒
但是如果最原始的OSS URL泄露,还是能进行访问。所以并不适合存储一些例如私密信息,付费课程源视频等

私有资源是默认任何人都不能直接访问文件,即使知道 URL 也不行。其需要配合签名URL,同时结合后端进行权限认证。例如在线课程平台只有再用户购买后才会开放权限
如果有权限,后端生成一个短时间有效的签名 URL,例如 5 分钟有效,这样用户可以在短时间内访问,过期后链接失效。即私有OSS签名下载方案

上传方案

根据上传链路不同可以分为两个方案

  • 方案1:客户端 -> 业务服务器 -> OSS
  • 方案2:客户端 -> OSS,业务服务器只负责发凭证/签名

当客户端不走业务服务器,就代表失去了自由控制的功能。例如我想对文件进行严格格式校验,只能让用户上传jpg格式文件,就无法做到
相反,如果链路经过业务服务器,我就能根据文件开头的二进制头特征(MIME TYPE)判断上传的文件是否属于特定格式

不同的场景用不同方案,比如用户头像上传,后端可以直接读取上传流,传输给oss不需要保存到本地。但是如果大文件需要上传于处理,会给业务服务器带来流量/带宽压力
下面是不同方案对于的不同处理流程

  • 方案1:
    1. 用户选择文件
    2. 前端 multipart/form-data 上传到后端
    3. 后端校验登录态、文件大小、文件类型
    4. 后端读取文件流
    5. 后端上传到 OSS
    6. OSS 返回 object key
    7. 后端写入数据库
    8. 后端返回文件访问地址或资源 ID
  • 方案2
    1. 用户请求业务后端:我要上传文件
    2. 后端校验用户身份和业务权限
    3. 后端生成临时上传凭证或签名
    4. 前端拿到凭证
    5. 前端直接上传到 OSS
    6. 上传成功后,前端通知后端
    7. 后端校验 object key,并写入数据库

方案1中,对于经过服务器的落盘方式,有不同的方案

  • 客户端 -> 后端内存/临时文件 -> OSS
  • 客户端 -> 后端磁盘 -> OSS
  • 客户端 -> 后端流式转发 -> OSS(网络IO+操作系统缓冲区)

方案2中,对于客户端直传方式,有不同的方案

  • 后端生成 STS 临时凭证,前端用 SDK 上传
  • 后端生成 Post Policy,前端用表单直传
  • 后端生成上传 Signed URL,前端 PUT 上传

客户端直传方式

1. 后端生成 STS 临时凭证,前端用 SDK 上传

STS 可以理解成:后端临时给前端发一张短期通行证。包含AccessKeyId,AccessKeySecret,SecurityToken,Expiration
后端可以限制

  • 只能上传到某个 bucket
  • 只能上传到 user-uploads/1001/ 目录
  • 只能有效 15 分钟
  • 不能删除文件
  • 不能读取其他文件

流程如下:

  1. 前端请求 /api/oss/sts
  2. 后端校验用户登录
  3. 后端向云厂商 STS 服务申请临时凭证
  4. 后端返回临时凭证给前端
  5. 前端用 OSS SDK 直传
  6. 前端把 object key 通知后端
  7. 后端写数据库

适合:

  • 大文件上传
  • 图片上传
  • 视频上传
  • App 端上传
  • Web 端上传
  • 需要分片上传的场景

这是现在非常常见的方案。

2. 后端生成 Post Policy,前端用表单直传

Post Policy 可以理解成:后端提前签一个上传规则,前端拿这个规则用表单上传到 OSS
它通常限制:

  • 上传路径前缀
  • 文件大小
  • Content-Type
  • 过期时间

流程如下:

  1. 前端请求 /api/oss/policy
  2. 后端返回 policy、signature、dir、host
  3. 前端构造 FormData
  4. 前端 POST 到 OSS
  5. OSS 返回成功
  6. 前端通知后端保存记录

优点是简单,适合图片、普通文件上传。
缺点是复杂控制能力不如 STS 灵活。

3. 后端生成上传 Signed URL,前端 PUT 上传

还有一种方式是:后端生成一个带签名的 PUT URL。

前端拿到后,PUT 文件内容到这个 URL
流程如下:

  1. 前端告诉后端:我要上传 avatar.png
  2. 后端生成 object key
  3. 后端生成 5 分钟有效的 PUT 签名 URL
  4. 前端用 fetch/axios PUT 文件到这个 URL
  5. 上传成功后,前端通知后端

这种方案的特点是:一个签名 URL 通常对应一个具体对象
例如后端生成:uploads/user_1001/avatar.png。前端只能往这个对象上传。

它适合:

  • 上传单个确定文件
  • 权限控制简单
  • 不想让前端接触 STS
  • 后端希望强控制 object key

但是如果要做分片上传、大文件断点续传,通常 STS + SDK 更方便。

下载方案

公共资源的下载,一是可以让返回给前端访问固定OSS Bucket,但是没有权限控制。二是后端隐藏真实路径存储地址,下载走后端转发

私有资源不能直接访问,需要后端要生成签名URL,对应上传方案中的Signed URL,即服务器为私有文件生成带过期时间的 GET 方法预签名 URL,让客户端临时下载文件

sequenceDiagram  
	participant U as 用户浏览器  
	participant B as 业务后端  
	participant DB as 数据库  
	participant OSS as 私有 OSS Bucket  
	  
	U->>B: 请求下载 fileId  
	B->>B: 校验登录态 / JWT / Session  
	B->>DB: 查询 fileId 对应的 objectKey 和权限  
	DB-->>B: 返回 objectKey、ownerId、资源状态  
	B->>B: 判断用户是否有访问权限  
	B->>B: 使用 AccessKey 或 STS 凭证生成 GET 签名 URL  
	B-->>U: 返回签名 URL  
	U->>OSS: 直接访问签名 URL  
	OSS->>OSS: 校验签名、过期时间、权限  
	OSS-->>U: 返回文件内容

当客户端访问URL时,OSS会校验,随后触发下载
对于这种方式,服务器数据库需要记录下面字段

file_id: 10001  
owner_id: 20001  
bucket: itifei-01  
object_key: user-upload/20001/avatar/a.png
visibility: private

真正下载时,后端根据 object_key 临时生成签名 URL

sequenceDiagram  
	participant U as 用户  
	participant API as 后端 API  
	participant Auth as 鉴权模块  
	participant DB as 数据库  
	participant Signer as OSS SDK 签名器  
	participant OSS as OSS  
	  
	U->>API: GET /api/files/10001/share-url  
	API->>Auth: 校验用户身份  
	Auth-->>API: userId = 20001  
	  
	API->>DB: 查询 fileId = 10001  
	DB-->>API: objectKey = user-upload/20001/a.png  
	  
	API->>API: 判断 userId 是否有权限  
	API->>Signer: 生成 GET 预签名 URL,有效期 1 小时  
	Signer-->>API: signedUrl  
	  
	API-->>U: 返回 signedUrl  
	U->>OSS: GET signedUrl  
	OSS-->>U: 文件内容

流程如下:

  1. 用户请求:我要看课程视频
  2. 后端校验用户是否购买课程
  3. 后端查询视频 object key
  4. 后端生成短期有效的下载 URL
  5. 前端拿 URL 播放或下载



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码