如果你曾经在前端项目里引入 ali-oss,然后看着打包体积飙升,你就会理解我为什么要写这篇文章。
痛点:ali-oss 的"重量级"烦恼
让我们直接看数据:
| 包 | Minified | Gzipped |
|---|---|---|
| ali-oss (v6.23.0) | 675.3 KB | 172.2 KB |
| @aws-sdk/client-s3 (v3.958.0) | 394.7 KB | 99.0 KB |
172KB——这是一个用于上传文件的 SDK 的 gzip 后体积。对于一个只需要生成签名 URL 让用户直接上传到 OSS 的场景,这个代价太大了。
更糟糕的是,ali-oss 承载了太多历史包袱:Browser 和 Node.js 双环境支持、各种边缘 case 的 polyfill、以及一些你可能永远用不到的功能。
转折:发现 OSS 的"隐藏协议"
在尝试自己实现 V4 签名算法(是的,我做了这件事)后,我发现了一个更优雅的解决方案:
阿里云 OSS 官方支持 Amazon S3 兼容 API。
这意味着你可以直接用 AWS 官方的 S3 SDK 来操作阿里云 OSS。不需要魔改,不需要 hack,官方背书。
决策树:什么时候用 S3 SDK?
在决定切换之前,先确认你的使用场景。
✅ 推荐使用 S3 SDK 的场景
-
前端直传(Presigned URL)
- 只需要生成签名 URL,让浏览器直接 PUT/GET 文件
- 这是最常见的场景,也是 S3 SDK 最大的优势
-
基础文件操作
- 上传、下载、删除、列表
- 分片上传(Multipart Upload)
-
多云架构
- 需要同时支持 AWS S3、Cloudflare R2、MinIO、阿里云 OSS
- 一套代码,多云兼容
-
追求最小依赖
- 对 bundle size 敏感的前端项目
- Serverless 函数(冷启动时间敏感)
⚠️ 仍需使用 ali-oss 的场景
-
视频处理
- 通过 S3 协议调用时,
x-oss-process参数不支持video/类型 - 只支持
image/和style/处理
- 通过 S3 协议调用时,
-
OSS 特有功能
- 图片样式管理
- 部分高级生命周期规则
- OSS-HDFS 等阿里云特有能力
-
遗留系统改造成本高
- 已有大量 ali-oss 代码,且运行良好
- 不值得为了省几十 KB 做大规模重构
实战:S3 SDK 连接阿里云 OSS
下面是一个完整的实现示例。
安装依赖
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
注意:
@aws-sdk/s3-request-presigner是扩展包,必须配合@aws-sdk/client-s3使用。
生成签名 URL
// presign.ts
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
// 创建 S3 客户端,指向阿里云 OSS
const client = new S3Client({
region: "oss-cn-hangzhou", // 你的 OSS Region
endpoint: "https://oss-cn-hangzhou.aliyuncs.com", // 关键:指定 OSS Endpoint
credentials: {
accessKeyId: "YOUR_ACCESS_KEY_ID",
secretAccessKey: "YOUR_ACCESS_KEY_SECRET",
},
// 阿里云 OSS 仅支持 Virtual-Hosted 风格(默认即是)
forcePathStyle: false,
});
// 生成上传用的签名 URL
async function getUploadUrl(bucket: string, key: string) {
const command = new PutObjectCommand({
Bucket: bucket,
Key: key,
});
const url = await getSignedUrl(client, command, {
expiresIn: 3600, // 1 小时有效期
});
return url;
}
// 生成下载用的签名 URL
async function getDownloadUrl(bucket: string, key: string) {
const command = new GetObjectCommand({
Bucket: bucket,
Key: key,
});
return await getSignedUrl(client, command, {
expiresIn: 3600,
});
}
关键配置说明
| 配置项 | 说明 |
|---|---|
region |
OSS 的 Region ID,如 oss-cn-hangzhou |
endpoint |
完整的 OSS Endpoint URL |
forcePathStyle |
必须为 false,OSS 仅支持 Virtual-Hosted 风格 |
已知差异与注意事项
在将 S3 SDK 用于 OSS 时,有几个关键差异需要注意:
1. 仅支持 Virtual-Hosted 请求风格
OSS 不支持 Path-Style 请求。也就是说,URL 必须是:
- ✅
https://bucket-name.oss-cn-hangzhou.aliyuncs.com/key - ❌
https://oss-cn-hangzhou.aliyuncs.com/bucket-name/key
S3 SDK 默认使用 Virtual-Hosted,所以一般不需要特别处理。
2. ETag 大小写
- OSS 返回的 ETag 是大写
- S3 返回的 ETag 是小写
如果你的代码依赖 ETag 进行校验,请忽略大小写。
3. 存储类型映射
| S3 | OSS 对应 |
|---|---|
STANDARD |
标准存储 |
STANDARD_IA |
低频访问 |
GLACIER |
归档存储 |
4. ACL 支持范围
OSS 在 S3 模式下仅支持以下 ACL:
privatepublic-readpublic-read-write
其他 S3 ACL(如 bucket-owner-full-control)不被支持。
附录:阿里云 OSS S3 兼容 API 完整清单
以下是阿里云官方文档确认支持的 S3 API 操作:
Bucket 操作
| 操作 | 支持状态 |
|---|---|
| PutBucket | ✅ |
| DeleteBucket | ✅ |
| GetBucket (ListObjects) | ✅ |
| GetBucketV2 (ListObjectsV2) | ✅ |
| GetBucketACL | ✅ |
| GetBucketLifecycle | ✅ |
| GetBucketLocation | ✅ |
| GetBucketLogging | ✅ |
| HeadBucket | ✅ |
| PutBucketACL | ✅ |
| PutBucketLifecycle | ✅ |
| PutBucketLogging | ✅ |
Object 操作
| 操作 | 支持状态 |
|---|---|
| DeleteObject | ✅ |
| DeleteObjects | ✅ |
| GetObject | ✅ |
| GetObjectACL | ✅ |
| HeadObject | ✅ |
| PostObject | ✅ |
| PutObject | ✅ |
| PutObjectCopy | ✅ |
| PutObjectACL | ✅ |
Multipart 操作
| 操作 | 支持状态 |
|---|---|
| InitiateMultipartUpload | ✅ |
| AbortMultipartUpload | ✅ |
| CompleteMultipartUpload | ✅ |
| ListParts | ✅ |
| UploadPart | ✅ |
| UploadPartCopy | ✅ |
总结
选择 S3 SDK 如果你:
- 只需要签名 URL 进行前端直传
- 追求最小 bundle size
- 需要多云兼容架构
继续使用 ali-oss 如果你:
- 需要视频处理 (
x-oss-process=video/) - 依赖 OSS 特有功能
- 已有稳定运行的遗留代码
对于大多数现代应用来说,S3 SDK 是更轻量、更通用、更面向未来的选择。毕竟,谁不想让自己的 bundle 瘦身 42% 呢?