OSS直传使用说明.md 7.5 KB

OSS直传优化方案使用说明

概述

本方案实现了阿里云OSS直传功能,支持:

  • ✅ 前端直接上传到OSS(不经过后端服务器)
  • ✅ 分片上传(支持大文件)
  • ✅ 断点续传
  • ✅ 上传进度查询
  • ✅ 上传回调验证

核心优势

  1. 性能提升:文件直接上传到OSS,不经过后端服务器,减少服务器带宽和IO压力
  2. 支持大文件:通过分片上传,支持超大文件上传
  3. 断点续传:上传中断后可以继续上传,无需重新开始
  4. 安全性:使用签名验证,确保上传安全

API接口说明

1. 生成OSS直传签名

接口地址POST /oss/direct/signature

请求参数

  • dir(可选):上传目录,默认 video/
  • fileName(可选):文件名,不传则自动生成UUID
  • maxSize(可选):最大文件大小(字节),默认100MB
  • expireTime(可选):过期时间(毫秒),默认1小时

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "accessKeyId": "LTAI5t...",
    "policy": "eyJleHBpcmF0aW9uIjoi...",
    "signature": "abc123...",
    "dir": "video/",
    "host": "https://alien-volume.oss-cn-beijing.aliyuncs.com",
    "expire": "1704067200",
    "ossKey": "video/uuid-filename.mp4",
    "callbackUrl": "",
    "callbackBody": ""
  }
}

2. 初始化分片上传

接口地址POST /oss/direct/multipart/init

请求参数

  • ossKey(必需):OSS文件路径,如 video/filename.mp4

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "uploadId": "abc123...",
    "ossKey": "video/filename.mp4"
  }
}

3. 上传分片

接口地址POST /oss/direct/multipart/upload

请求参数

  • ossKey(必需):OSS文件路径
  • uploadId(必需):上传ID
  • partNumber(必需):分片序号(从1开始)
  • partData(必需):分片数据(二进制)

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "partNumber": 1,
    "eTag": "\"abc123...\""
  }
}

4. 完成分片上传(合并)

接口地址POST /oss/direct/multipart/complete

请求参数

  • ossKey(必需):OSS文件路径
  • uploadId(必需):上传ID
  • partETags(必需):所有分片的ETag列表(JSON数组)

请求Body示例

[
  {"partNumber": 1, "eTag": "\"abc123...\""},
  {"partNumber": 2, "eTag": "\"def456...\""},
  {"partNumber": 3, "eTag": "\"ghi789...\""}
]

响应示例

{
  "code": 200,
  "success": true,
  "data": {
    "fileUrl": "https://alien-volume.oss-cn-beijing.aliyuncs.com/video/filename.mp4",
    "ossKey": "video/filename.mp4"
  }
}

5. 取消分片上传

接口地址POST /oss/direct/multipart/abort

请求参数

  • ossKey(必需):OSS文件路径
  • uploadId(必需):上传ID

6. 查询已上传的分片(断点续传)

接口地址GET /oss/direct/multipart/list

请求参数

  • ossKey(必需):OSS文件路径
  • uploadId(必需):上传ID

响应示例

{
  "code": 200,
  "success": true,
  "data": [
    {
      "partNumber": 1,
      "eTag": "\"abc123...\"",
      "size": 5242880
    },
    {
      "partNumber": 2,
      "eTag": "\"def456...\"",
      "size": 5242880
    }
  ]
}

7. OSS上传回调验证

接口地址POST /oss/direct/callback

请求头

  • Authorization:OSS回调的Authorization头

请求参数

  • pubKeyUrl:公钥URL
  • callbackBody:回调Body(JSON格式)

使用流程

方式一:简单直传(小文件,<100MB)

  1. 调用 /oss/direct/signature 获取签名
  2. 前端使用签名直接POST到OSS
  3. 上传成功后,OSS会返回文件URL

方式二:分片上传(大文件,>100MB)

  1. 调用 /oss/direct/multipart/init 初始化分片上传,获取 uploadId
  2. 将文件分成多个分片(建议每个分片5-10MB)
  3. 对每个分片调用 /oss/direct/multipart/upload 上传
  4. 所有分片上传完成后,调用 /oss/direct/multipart/complete 合并分片
  5. 获取最终的文件URL

方式三:断点续传

  1. 调用 /oss/direct/multipart/list 查询已上传的分片
  2. 只上传未完成的分片
  3. 所有分片完成后,调用 /oss/direct/multipart/complete 合并

前端集成示例

JavaScript示例(简单直传)

// 1. 获取签名
const response = await fetch('/oss/direct/signature?dir=video/&fileName=test.mp4', {
  method: 'POST'
});
const { data } = await response.json();

// 2. 构建FormData
const formData = new FormData();
formData.append('key', data.ossKey);
formData.append('policy', data.policy);
formData.append('OSSAccessKeyId', data.accessKeyId);
formData.append('signature', data.signature);
formData.append('file', file); // 文件对象

// 3. 直接上传到OSS
const uploadResponse = await fetch(data.host, {
  method: 'POST',
  body: formData
});

// 4. 上传成功,获取文件URL
const fileUrl = data.host + '/' + data.ossKey;

JavaScript示例(分片上传)

// 1. 初始化分片上传
const initResponse = await fetch('/oss/direct/multipart/init', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: `ossKey=video/test.mp4`
});
const { data: initData } = await initResponse.json();
const { uploadId, ossKey } = initData;

// 2. 分片上传
const chunkSize = 5 * 1024 * 1024; // 5MB
const chunks = Math.ceil(file.size / chunkSize);
const partETags = [];

for (let i = 0; i < chunks; i++) {
  const start = i * chunkSize;
  const end = Math.min(start + chunkSize, file.size);
  const chunk = file.slice(start, end);
  
  const chunkResponse = await fetch('/oss/direct/multipart/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      ossKey,
      uploadId,
      partNumber: i + 1,
      partData: await chunk.arrayBuffer()
    })
  });
  
  const { data: partData } = await chunkResponse.json();
  partETags.push({
    partNumber: partData.partNumber,
    eTag: partData.eTag
  });
}

// 3. 完成分片上传
const completeResponse = await fetch('/oss/direct/multipart/complete', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    ossKey,
    uploadId,
    partETags
  })
});

const { data: completeData } = await completeResponse.json();
const fileUrl = completeData.fileUrl;

注意事项

  1. 文件大小限制:建议单个分片5-10MB,最多支持10000个分片
  2. 签名过期:签名默认1小时过期,过期后需要重新获取
  3. 错误处理:上传失败时,可以调用 /oss/direct/multipart/abort 清理未完成的分片
  4. 安全性:生产环境建议配置OSS回调,验证上传结果
  5. 性能优化:大文件建议使用分片上传,可以并行上传多个分片提升速度

配置说明

确保在 application.yml 或 Nacos 中配置了以下OSS参数:

ali:
  oss:
    accessKeyId: your-access-key-id
    accessKeySecret: your-access-key-secret
    endPoint: oss-cn-beijing.aliyuncs.com
    bucketName: your-bucket-name

故障排查

  1. 签名验证失败:检查AccessKey和Secret是否正确
  2. 分片上传失败:检查分片大小是否合理(建议5-10MB)
  3. 合并失败:确保所有分片都已成功上传,且ETag正确
  4. 回调验证失败:检查公钥URL是否可访问