如果你曾经在前端项目里引入 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 的场景

  1. 前端直传(Presigned URL)

    • 只需要生成签名 URL,让浏览器直接 PUT/GET 文件
    • 这是最常见的场景,也是 S3 SDK 最大的优势
  2. 基础文件操作

    • 上传、下载、删除、列表
    • 分片上传(Multipart Upload)
  3. 多云架构

    • 需要同时支持 AWS S3、Cloudflare R2、MinIO、阿里云 OSS
    • 一套代码,多云兼容
  4. 追求最小依赖

    • 对 bundle size 敏感的前端项目
    • Serverless 函数(冷启动时间敏感)

⚠️ 仍需使用 ali-oss 的场景

  1. 视频处理

    • 通过 S3 协议调用时,x-oss-process 参数不支持 video/ 类型
    • 只支持 image/style/ 处理
  2. OSS 特有功能

    • 图片样式管理
    • 部分高级生命周期规则
    • OSS-HDFS 等阿里云特有能力
  3. 遗留系统改造成本高

    • 已有大量 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:

  • private
  • public-read
  • public-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% 呢?


参考资料:阿里云 OSS 官方文档 - S3 兼容 API