# OSS直传优化方案使用说明 ## 概述 本方案实现了阿里云OSS直传功能,支持: - ✅ 前端直接上传到OSS(不经过后端服务器) - ✅ 分片上传(支持大文件) - ✅ 断点续传 - ✅ 上传进度查询 - ✅ 上传回调验证 ## 核心优势 1. **性能提升**:文件直接上传到OSS,不经过后端服务器,减少服务器带宽和IO压力 2. **支持大文件**:通过分片上传,支持超大文件上传 3. **断点续传**:上传中断后可以继续上传,无需重新开始 4. **安全性**:使用签名验证,确保上传安全 ## API接口说明 ### 1. 生成OSS直传签名 **接口地址**:`POST /oss/direct/signature` **请求参数**: - `dir`(可选):上传目录,默认 `video/` - `fileName`(可选):文件名,不传则自动生成UUID - `maxSize`(可选):最大文件大小(字节),默认100MB - `expireTime`(可选):过期时间(毫秒),默认1小时 **响应示例**: ```json { "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` **响应示例**: ```json { "code": 200, "success": true, "data": { "uploadId": "abc123...", "ossKey": "video/filename.mp4" } } ``` ### 3. 上传分片 **接口地址**:`POST /oss/direct/multipart/upload` **请求参数**: - `ossKey`(必需):OSS文件路径 - `uploadId`(必需):上传ID - `partNumber`(必需):分片序号(从1开始) - `partData`(必需):分片数据(二进制) **响应示例**: ```json { "code": 200, "success": true, "data": { "partNumber": 1, "eTag": "\"abc123...\"" } } ``` ### 4. 完成分片上传(合并) **接口地址**:`POST /oss/direct/multipart/complete` **请求参数**: - `ossKey`(必需):OSS文件路径 - `uploadId`(必需):上传ID - `partETags`(必需):所有分片的ETag列表(JSON数组) **请求Body示例**: ```json [ {"partNumber": 1, "eTag": "\"abc123...\""}, {"partNumber": 2, "eTag": "\"def456...\""}, {"partNumber": 3, "eTag": "\"ghi789...\""} ] ``` **响应示例**: ```json { "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 **响应示例**: ```json { "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示例(简单直传) ```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示例(分片上传) ```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参数: ```yaml 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是否可访问