☰
Spring Boot对接阿里云OSS文件上传:从签名直传到安全回调实战
2026/9/26 17:46:03 网站建设 项目流程

做后端这些年,十有八九的项目最后都会撞上同一个需求:文件上传。早期我习惯把文件扔到本地磁盘,单机的时候没感觉,等用户量上来,磁盘告警、备份麻烦、域名换乱、扩展困难,每一样都够折腾一阵子。后来把对象存储迁到阿里云OSS,整套链路从设计到落地,文档里其实很多细节要靠自己踩。这篇文章就把Spring Boot对接阿里云OSS做文件上传的完整流程重新捋一遍,从开通服务、初始化SDK、封装签名接口、配置回调校验,到开发阶段常见的跨域、超时、命名坑,以及文件上传安全边界,尽量做到看完能直接照着落地。

这篇内容适合谁看?我自己定位是两类人:一是刚接触OSS上传、对着官方文档不知道从哪下手的Java后端;二是已经跑通了基本上传、但发现回调校验或安全策略还悬着的老开发。后者可以直接跳到第四章和第五章。文章中涉及的都是生产环境验证过的做法,代码以Spring Boot 2.7.x为基础,SDK用的是aliyun-sdk-oss 3.17.x,新版本大同小异。

1. 为什么我不建议把文件直接存本地:OSS选型前后的思考

1.1 本地存储的三类痛点和OSS的对应解法

先说痛点。很多人一开始图省事,把上传的文件直接塞到项目的静态目录或某块挂载盘里。小项目确实能跑,但到一定规模后问题就暴露出来了。

第一是磁盘容量不可控。用户头像、商品详情图、日志文件、合同PDF,这些文件一旦多起来,单机磁盘很快见底。扩容就得加盘,加盘就意味着停机维护或者迁移数据,成本直接上去了。

第二是备份和冗余成本高。本地文件只能自己做副本,搞个定时任务rsync到另一台机器,或者买NAS,这些方案不是不能用,但没有一种能像OSS那样自带跨可用区冗余。OSS默认就把数据做了多副本,这一点对中小团队来说是省心的。

第三是访问链路和域名管理混乱。本地文件如果要走HTTPS,得自己搞证书、配Nginx、处理负载均衡。而OSS天然支持HTTPS、CDN加速、自定义域名绑定,上传后拿到的URL就是可直接访问的公网地址,基本不用再单独维护一套静态资源服务。

1.2 三个必须理解的基础概念:Region、Bucket、Object

开始写代码之前,建议先想清楚OSS的三个基本概念,不然你会被文档里的各种名词绕晕。

  • Region(地域):指OSS数据中心所在的物理区域,比如华东1(杭州)、华北2(北京)。选Region要遵循就近原则,服务器在上海,Bucket最好就建在华东2(上海),内网访问还免流量费。
  • Bucket(存储空间):可以理解为一个全局唯一命名的文件仓库。名称在OSS内是全局唯一的,所以创建的时候经常发现你心仪的名字被占了,加个后缀就好。
  • Object(对象):就是存在Bucket里的文件。OSS里的每个文件都叫Object,它有唯一的Key,这个Key就是文件的完整路径名,比如avatar/2024/04/01/xxx.jpg。

这三个概念弄清楚后,你再去看OSS的API文档和SDK示例代码,基本能对得上号。另外还要提前做好一个决定:Bucket的读写权限。如果只是普通业务文件,不建议选公共读,更不建议选公共读写,后续章节我会专门讲权限策略。

2. 动手前的基础准备:从开通OSS到创建Bucket

2.1 创建Bucket时最容易被忽略的参数

流程上,先到阿里云控制台开通OSS服务,然后创建Bucket。创建的时候有几个参数值得多看一眼。

  • Bucket名称:全局唯一,命名规则是只能包含小写字母、数字和短横线,不能以短横线开头或结尾。这个名称会出现在后续的访问域名里,所以尽量起得有意义一点。
  • 地域:一旦创建就不能修改,所以创建前想清楚。如果是做测试,选离你最近的地域就好;如果是生产,最好选和业务服务器相同的地域,走内网Endpoint可以省公网流量费。
  • 读写权限:这里有一个我强烈建议的选择——私有(Private)。原因后面详细说。如果你只是想临时测试上传,选公共读也行,但线上千万别图省事。
  • 版本控制:默认关闭。如果业务上有文件误删回滚需求,可以后续在Bucket设置里开启,不用创建时纠结。

我见过很多人在这一步直接把权限选成公共读,理由是"反正图片URL要给人看"。其实图片URL完全可以通过签名URL方式临时授权,或者绑CDN域名来做,不需要把整个Bucket裸奔。

2.2 AccessKey的创建方式:别拿主账号到处贴

这一步很多人会犯一个毛病:直接用主账号的AccessKey(AccessKey ID / AccessKey Secret)写进配置文件。主账号的AccessKey权限是全部资源权限,一旦泄露,整个账号下的资源都遭殃。正确做法是创建RAM子账号,并把这个子账号的权限范围限制在OSS操作上。

控制台里的操作路径是:RAM访问控制 -> 用户 -> 创建用户 -> 给用户选择"编程访问"方式,会生成一组AccessKey。创建完之后,给这个用户添加权限策略,一般用系统自带的AliyunOSSFullAccess就够了,如果你有多环境隔离或者更细粒度的需求,可以单独写自定义策略,只允许访问某个Bucket:

{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": "acs:oss:*:*:your-bucket-name/*" } ] }

这段JSON的意思是仅允许向指定Bucket上传文件,其他的OSS操作全部拒绝。强烈建议把RAM授权这件事当成上线流程的一部分,别把方便当安全。

2.3 引入依赖并搭好配置骨架

项目是Maven构建的话,引入阿里云OSS的SDK依赖:

<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.17.4</version> </dependency>

当前项目用3.17.4锁版本,新项目可以适当升级。如果构建时遇到javax.xml.bind相关的包缺失,通常是JDK版本过高导致的,需要在pom里额外引入jakarta.xml.bind-api和jaxb-runtime。这个坑常在JDK 11以上的环境出现,先记着。

依赖引入之后,在application.yml里加OSS配置:

aliyun: oss: endpoint: oss-cn-hangzhou.aliyuncs.com access-key-id: your-access-key-id access-key-secret: your-access-key-secret bucket-name: your-bucket-name # 自定义回调地址,稍后代码里会用到 callback-url: https://api.example.com/oss/callback

注意这里有个细节:Endpoint分公网和内网两种形式。公网是oss-cn-hangzhou.aliyuncs.com,内网是oss-cn-hangzhou-internal.aliyuncs.com。如果你的应用跑在阿里云的ECS上,且ECS和OSS在同一个地域,强烈建议使用内网Endpoint,上传速度快、不产生公网下行流量费。

3. 上传方案怎么选:后端转发与签名直传的对比

3.1 方案一:后端接收文件再转发到OSS

最容易想到的上传方式是:前端把文件POST给后端,后端读成InputStream,再调用OSS SDK的putObject方法把流写入OSS。实现上非常简单,核心就一行:

ossClient.putObject(bucketName, objectKey, inputStream);

但实际生产中我不推荐用这个方案处理大文件。原因有三点:

第一,后端服务器成了流量瓶颈。每次上传都先到后端再转发OSS,相当于后端机器要承担所有上传流量。带宽不大的服务器,一个100MB的文件就可能拖垮其他接口响应。

第二,上传超时风险高。前端到后端、后端到OSS是两段链路,任何一段慢,HttpServletRequest就会等待很久,体验很差。

第三,浪费服务器磁盘和CPU。文件先落临时目录再上传,或者全程在内存里转,都会占用不必要的资源。

3.2 方案二:服务端签名、前端直传OSS

更优雅的做法是服务端签名直传。核心思路是:后端不接触文件内容,只负责生成一份带有过期时间的上传凭证(Policy),前端拿到凭证后,直接把文件以表单方式POST到OSS的Endpoint,OSS接收文件后返回结果,或者触发配置好的回调接口让后端感知上传完成。

关键点在于:上传凭证是后端用AccessKeySecret对一段策略文本加签生成的,前端只有凭证没有Secret,所以拿不到你的账号密钥。同时凭证里可以限制上传目录、文件大小、有效期,这比后端中转灵活得多。

3.3 一个表决定方案

两种方案取舍,我经常直接用一张表给团队讲清楚:

对比项后端转发签名直传
服务端带宽占用高,所有文件经过后端低,后端只处理签名和回调
上传速度受后端带宽限制直接走OSS节点,速度快
服务端CPU/内存有额外开销几乎没有
文件大小限制受网关/容器限制单文件最大5GB
安全性可控性好需要严格校验签名参数
实现复杂度低中等

结论很明确:除了一些需要在后端做内容处理的场景(比如压缩图片、解析Excel、病毒扫描),签名直传是更合理的默认方案。我的项目最终采用的就是"服务端签名 + 前端直传 + OSS回调通知后端"的组合。

4. 核心实现:配置骨架、签名接口与回调校验

4.1 配置参数绑定到Java Bean

写代码的第一步是把YAML配置绑定成一个配置类,避免在业务代码里到处写@Value。

@Component @ConfigurationProperties(prefix = "aliyun.oss") public class OssProperties { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; private String callbackUrl; // getter / setter 省略 }

@ConfigurationProperties的prefix对应application.yml里的aliyun.oss前缀,字段名和配置key要一一对应。启动项目后如果配置注入失败,Spring会在启动阶段就报错,不会等到调用时才暴露,这点很省心。

4.2 生成Policy签名和上传凭证

核心的签名逻辑我封装在一个OssSignatureService里,方法返回一个Map,前端直接取里面的字段组装表单即可。

@Service public class OssSignatureService { private final OSS ossClient; private final OssProperties ossProperties; public OssSignatureService(OssProperties properties) { this.ossProperties = properties; this.ossClient = new OSSClientBuilder().build( properties.getEndpoint(), properties.getAccessKeyId(), properties.getAccessKeySecret() ); } public Map<String, String> createPolicy(String dir, long maxSize) { // 签名有效期,单位秒。建议30秒-10分钟,太短影响用户体验,太长有滥用风险 long expireTime = 30; long expireEndTime = System.currentTimeMillis() + expireTime * 1000; PolicyConditions policyConditions = new PolicyConditions(); // 限制上传文件大小,maxSize单位是字节,比如5MB就是 5 * 1024 * 1024 policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize); // 限制上传目录前缀,防止用户把文件传到别的路径下 policyConditions.addConditionItem(PolicyConditions.COND_STARTS_WITH, "$key", dir); String postPolicy = ossClient.generatePostPolicy(expireEndTime, policyConditions); String encodedPolicy = Base64.encodeToString(postPolicy.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); String postSignature = ossClient.calculatePostSignature(postPolicy); Map<String, String> result = new HashMap<>(); result.put("accessid", ossProperties.getAccessKeyId()); result.put("policy", encodedPolicy); result.put("signature", postSignature); result.put("dir", dir); result.put("host", "https://" + ossProperties.getBucketName() + "." + ossProperties.getEndpoint()); result.put("expire", String.valueOf(expireEndTime / 1000)); return result; } }

这里有几个信息需要解释。dir是允许上传的虚拟目录前缀,比如avatar/2024/04/01/,前端提交文件时,表单里的key字段必须是以dir开头的完整路径。maxSize限制单文件大小,OSS服务端会校验,超过直接拒绝。accessid传的是AccessKey ID,但签名必须由后端生成,AccessKey Secret始终不出现在任何客户端代码里。

4.3 上传完成后的回调校验

直传模式下,前端提交文件到OSS成功后,有两种方式让后端知道结果。一种是前端拿到OSS的返回结果再主动调后端接口,另一种是OSS在文件接收完成后直接向后端发一个HTTP回调。推荐后者,因为回调是服务端到服务端的通信,前端无法伪造,安全性更高。

开启回调,需要在前端表单里多带两个隐藏字段:x-oss-callback和x-oss-callback-var。x-oss-callback的值是一个URL编码后的JSON,示例:

{ "callbackUrl": "https://api.example.com/oss/callback", "callbackHost": "api.example.com", "callbackBody": "filename=${object}&size=${size}&mimeType=${mimeType}&bucket=${bucket}&etag=${etag}", "callbackBodyType": "application/x-www-form-urlencoded" }

后端收到这个回调后,必须做两件事:

第一,验证回调请求确实来自OSS。判断方法:取请求头中的Authorization、x-oss-pub-key-url、x-oss-request-id,用OSS文档提供的签名算法校验。核心代码如下:

@PostMapping("/oss/callback") public ResponseEntity<Map<String, Object>> callback(HttpServletRequest request) throws Exception { String authorization = request.getHeader("Authorization"); String pubKeyUrl = request.getHeader("x-oss-pub-key-url"); // 公钥URL可能包含特殊字符,需要URLDecoder解码后再请求公钥字符串 pubKeyUrl = URLDecoder.decode(pubKeyUrl, "UTF-8"); String pubKey = HttpClientUtil.doGet(pubKeyUrl); // 回调Body是请求体的原始字节 byte[] requestBodyBytes = getRequestBodyBytes(request); String requestBody = new String(requestBodyBytes, StandardCharsets.UTF_8); // 签名规则:Authorization = "OSS " + Base64(HMAC-SHA1(公钥, 回调Body)) String expectedSignature = "OSS " + signWithHmacSha1(pubKey, requestBody); if (!expectedSignature.equals(authorization)) { return ResponseEntity.status(403).build(); } // 解析回调Body,拿到objectKey等信息,落库 Map<String, String> params = parseFormBody(requestBody); FileRecord record = new FileRecord(); record.setObjectKey(params.get("filename")); record.setSize(Long.parseLong(params.get("size"))); fileRecordMapper.insert(record); Map<String, Object> result = new HashMap<>(); result.put("Status", "OK"); return ResponseEntity.ok(result); }

第二,处理完成业务后,必须返回一个具体的JSON响应给OSS,比如上面的{"Status":"OK"}。如果回调返回非200,OSS会认为上传失败,前端也会收到一个错误提示,这点联调时要格外注意。

4.4 Controller和统一返回结构

签名接口的Controller很简单,只负责接收请求参数然后透传:

@RestController @RequestMapping("/oss") public class OssController { private final OssSignatureService signatureService; @PostMapping("/policy") public Result<Map<String, String>> policy(@RequestParam String dir, @RequestParam(defaultValue = "5242880") long maxSize) { return Result.success(signatureService.createPolicy(dir, maxSize)); } }

返回结构我用了一套全局统一的Result<T>封装:code、msg、data三个字段,和公司内部其他接口风格保持一致,前端处理起来也统一。这一步没有技术难度,但建议在项目一开始就定好,不然后期每个接口返回都不一样很痛苦。

5. 安全边界:文件上传最容易翻车的地方

5.1 后缀黑名单为什么挡不住实际风险

互联网上关于文件上传漏洞的分析非常多,很多CTF题目和攻防演练中都能看到这类问题的影子。核心原因层出不穷:有些场景只做了简单的后缀黑名单,攻击者可以通过大小写绕过(如asp改成Asp或aSp)、双重扩展名绕过(如shell.jpg.php)、特殊符号绕过(如file.php.、file.php%00.jpg)等方式尝试突破。

更麻烦的是,某些服务器中间件存在解析特性差异,比如Apache在某些配置下会把test.php.jpg按PHP脚本来解析,或者对多后缀文件有不同处理逻辑。这些都不是靠拉一个黑名单就能覆盖的。所以我的原则是:文件名后缀统一走白名单,不在白名单内的文件一律拒绝。

5.2 前端限制与后端校验的双层配合

前端要限制上传类型,这是为了用户体验,比如input的accept=".jpg,.jpeg,.png,.gif,.pdf",以及上传组件里的类型判断。但前端限制只是防君子不防小人,真正可靠的是后端在回调阶段做二次校验。

后端能做的校验有三个层级:

  • 后缀白名单。比如只允许jpg/jpeg/png/gif/bmp/pdf/zip,这个列表按业务需求定。
  • Content-Type校验。比如JPEG的MIME类型应该是image/jpeg,如果上传的文件声称是图片但Content-Type是application/x-php,直接拒绝。
  • Magic Number校验。这是更硬核的一招:读取文件开头几个字节判断真实类型。JPEG开头是FF D8 FF,PNG开头是89 50 4E 47,GIF开头是47 49 46 38。这种校验能拦截大部分改装后缀的伪装文件。

这里额外提一句:如果你处理的文件类型需要更深入的检测(比如PDF、Office文档),建议引入独立的文件识别库或者调用三方内容检测服务,单纯靠后缀和Content-Type远远不够。

5.3 私有读写与防盗链怎么配

我在第二章里反复强调Bucket权限选私有,这里就实打实讲下原因。如果Bucket是公共读,任何人拿到文件URL就能直接下载,没有时效限制。被爬虫抓取、被违规下载、产生大量外链流量费,都是可能发生的。

私有Bucket配合签名URL是更稳的做法。生成签名URL的方式:

URL url = ossClient.generatePresignedUrl( bucketName, objectKey, new Date(System.currentTimeMillis() + 3600 * 1000) );

这段代码生成一个有效期一小时的临时访问链接,链接里带了签名参数,过期自动失效。权限和时效都掌握在后端手里。如果业务上还要防止别人盗链,可以在Bucket的防盗链设置里配置Referer白名单,也可以接入CDN做更细粒度的访问控制。

5.4 objectKey的命名设计

objectKey就是文件在OSS里的存储路径,它的设计直接影响后续管理效率和安全。

第一,不要把用户上传的原始文件名直接作为objectKey。原因很直观:中文文件名、特殊字符、重名覆盖,任何一个都够你头疼。我常用的命名格式:

{业务类型}/{yyyyMMdd}/{UUID}.{ext}

比如用户头像:avatar/20240401/8f14e45fceea167a5a36dedd4bea2543.jpg。业务类型解决归类问题,日期目录方便后续生命周期清理,UUID避免重名冲突,后缀保留用于Content-Type判断。

第二,要注意路径穿越问题。如果你允许前端传目录参数,后端必须校验这个参数不能包含..和/开头,否则用户可能构造../../路径,把文件写到预期之外的目录。我通常在拼接key之前做一次正则校验:

if (!dir.matches("^[a-zA-Z0-9-_/]{1,100}/$")) { throw new IllegalArgumentException("invalid dir"); }

6. 联调踩坑记录:跨域、超时和文件名归一化

6.1 前端直传碰到CORS

签名直传模式下,前端会直接向OSS的Endpoint发起POST请求,这就涉及跨域。第一次联调时,前端给我报了个CORS错误:Access to XMLHttpRequest at 'https://bucket.oss-cn-hangzhou.aliyuncs.com' from origin 'http://localhost:8080' has been blocked by CORS policy。

原因很直接:OSS Bucket没有配置CORS规则。解决方式是在OSS控制台选择对应Bucket,进入"数据安全 -> 跨域设置",新建规则:

  • 来源:填前端域名,测试阶段可以写*,生产环境务必收敛到具体域名。
  • 允许Methods:至少勾选POST,因为直传用的是表单POST。
  • Allowed Headers:*即可,签名直传时前端需要带Content-Type等头。
  • Expose Headers:建议填ETag,有些业务需要读取上传后返回的ETag。

配置完成后等一分钟左右生效,再刷新页面重试。这个坑没有技术难度,但确实会卡住第一次做直传的人。

6.2 回调地址可达性与超时

OSS的回调是服务端发起的HTTP请求到你的接口,所以回调地址必须是公网可以访问的域名或IP。测试阶段我用过内网IP地址,结果OSS怎么都调不通。后来换成公网域名就好了。

还有两个时间参数要注意:一是OSS回调等待后端响应的超时时间默认是5秒,如果你的回调接口里有耗时的业务操作(比如写库、同步调用第三方服务),一定要把耗时控制在几秒以内,否则OSS会认为回调失败,前端会收到类似CallbackFailed的错误。二是回调失败后的重试次数,OSS默认有限定的重试机制,但业务侧最好不要依赖重试,最好把回调逻辑做成幂等的,重复调用不会产生重复数据。

6.3 中文文件名、空格和特殊字符

前端直传时,表单里的key字段如果包含中文或特殊字符,OSS会返回InvalidArgument或InvalidObjectName。这个问题常见于用户上传的文件名没有经过处理。

我的对策分两步:

  • 前端在组装表单参数前,对文件名统一做编码处理,建议用JavaScript的encodeURIComponent。
  • 后端在生成签名dir时,也对目录参数做归一化,只允许小写字母、数字、短横线和斜杠,中文目录名直接拒绝。

按之前的objectKey设计,key里的文件名部分直接用UUID,压根不会出现中文,只是这一步要在前端表单里写对逻辑。

6.4 排查问题时的关键日志位置

OSS的错误响应体往往是XML格式,前端和后端如果只看浏览器Network里的状态码很难定位原因。我自己的排查习惯是:

  • 优先看OSS返回的Code和Message字段,比如InvalidAccessKeyId说明AccessKey配错了,SignatureDoesNotMatch说明签名逻辑有问题,AccessDenied说明权限不足。
  • 后端开启SDK的日志开关,在开发环境把日志级别调到DEBUG。OSS Java SDK支持配置日志,能把每一步HTTP请求的细节打出来。
  • 如果回调失败,去OSS控制台的日志管理里查看请求日志,确认回调是否发出、返回码是多少。

这些信息比瞎猜有效得多,多花几分钟看日志,能省下半天联调时间。

7. 再往前走一步:大文件分片与断点续传

7.1 multipartUpload的完整流程

单文件如果超过一定大小(比如视频、压缩包,几百MB甚至几个GB),直传表单方式就不太合适了。OSS提供MultipartUpload分片上传能力,流程分三步:

  1. 初始化分片上传:调用InitiateMultipartUploadRequest,拿到一个全局唯一的uploadId。
  2. 并发上传分片:把文件切成固定大小的Part,每个Part关联uploadId和PartNumber,可以并发上传。
  3. 完成分片上传:所有Part传完后,收集每个Part的ETag和PartNumber,调用CompleteMultipartUploadRequest完成合并。

Java SDK中对应的实现逻辑大致是这样:

InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectKey); InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest); String uploadId = initResult.getUploadId(); // 假设文件分片列表已经准备好 List<PartETag> partETags = new ArrayList<>(); for (int i = 0; i < partCount; i++) { UploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.setBucketName(bucketName); uploadPartRequest.setKey(objectKey); uploadPartRequest.setUploadId(uploadId); uploadPartRequest.setPartNumber(i + 1); uploadPartRequest.setInputStream(partStream); uploadPartRequest.setPartSize(partSize); UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest); partETags.add(uploadPartResult.getPartETag()); } CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest( bucketName, objectKey, uploadId, partETags); ossClient.completeMultipartUpload(completeRequest);

官方SDK还提供了UploadFileRequest这种封装好的断点续传上传接口,底层自动处理分片和断点记录,适合在服务端本地有完整文件路径的场景。前端上传场景一般也就是把文件切片后并行POST到OSS,相对复杂一些,但没有本质区别。

7.2 断点续传和追加上传的选用场景

断点续传不是所有业务都需要的。我自己的判断标准是:

  • 文件大于100MB,且用户网络不稳定,值得投入做切片续传。
  • 文件小于10MB,直接用普通直传就完了,不要为了炫技增加前端复杂度。
  • 日志追加、渐进写入场景,用AppendObject更合适,比如物联网设备上报的数据文件。AppendObject可以把数据不断追加到同一个Object,最多追加10000次。

7.3 生命周期管理和存储类型

OSS另外一个容易忽略但又很实用的配置是生命周期规则。比如你可以设置:临时上传目录temp/下的文件,超过7天自动删除;avatar/目录下的历史头像,180天后自动转归档存储。这些规则都在控制台配置,不需要写代码,但能帮你省掉一堆手动清理的脚本。

存储类型选择也值得提一嘴:标准存储适合频繁访问;低频访问适合月内偶尔访问的数据;归档存储适合长期不访问的备份数据,但取回要额外付费和等待时间。上传的Object如果对实时性要求不高,我习惯在初始化ObjectMetadata时设置存储类型,避免默认全部是标准存储,成本高不少。

最后补一句经验

OSS上传这套链路,代码写起来其实没多少行,真正价值在细节的安全和边界处理上。我个人在实际项目中的体验是:前期把Bucket权限、RAM账号、白名单校验、回调签名这四件事一次性做对,后面上线后基本不用再回头补漏洞。如果每一样都图省事,后期查一次安全日志就够你熬夜好几宿的。建议你也从一个小场景开始——先用代码跑通图片上传,再加白名单和回调校验,最后再扩展大文件分片。这条路走顺,其他对象存储(MinIO、腾讯云COS)换起来也是同构操作,一通百通。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询