目錄
一、項目目標
二、騰訊云 COS 基本配置
1. 創建存儲桶
2. 獲取 API 密鑰
3. 設置跨域規則(CORS)
三、后端(Spring Boot)實現
1. 依賴配置
2. 配置騰訊云 COS(application.yml)
3. 初始化 COS 客戶端
4. 文件上傳接口
(1)普通上傳
(2)分片上傳接口
① 初始化分片上傳
② 上傳分片
③ 合并分片
四、前端(Vue2)實現
1. 安裝依賴
2. 分片上傳邏輯
五、注意事項與優化
1. 分片大小限制
2. 并發上傳優化
3. 斷點續傳支持
4. 安全性增強
六、總結
一、項目目標
實現基于騰訊云 COS 的 大文件分片上傳 和 普通文件上傳 功能,前后端分離架構,采用 Vue2 + Spring Boot + YML 配置方式,并覆蓋以下注意事項:
- 分片上傳大小限制
- 并發上傳優化
- 斷點續傳支持
- 安全性增強(避免暴露密鑰)
- 跨域規則配置(CORS)
二、騰訊云 COS 基本配置
1. 創建存儲桶
登錄騰訊云控制臺 → 對象存儲 COS → 創建存儲桶:
- 存儲桶名稱:
your-bucket-name-1250000000
- 地域:
ap-beijing
(根據需求選擇) - 權限設置:私有讀寫
2. 獲取 API 密鑰
前往 API 密鑰管理 頁面,創建或使用已有 SecretId/SecretKey。
? 安全建議:前端禁止直接使用 SecretId/SecretKey,應通過后端代理或使用 STS 臨時密鑰。
3. 設置跨域規則(CORS)
前往 權限管理 → 跨域規則,添加以下規則:
{"allowedOrigin": ["*"],"allowedMethod": ["GET", "POST", "PUT", "HEAD"],"allowedHeader": ["*"],"exposeHeader": [],"maxAgeSeconds": 3000
}
三、后端(Spring Boot)實現
1. 依賴配置
<dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 騰訊云 COS SDK --><dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.2.4</version></dependency><!-- 工具類 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>
</dependencies>
2. 配置騰訊云 COS(application.yml
)
tencent:cos:secret-id: YOUR_SECRET_IDsecret-key: YOUR_SECRET_KEYregion: ap-beijingbucket-name: your-bucket-name-1250000000
3. 初始化 COS 客戶端
import com.qcloud.cos.COSClient;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.region.Region;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CosConfig {@Value("${tencent.cos.secret-id}")private String secretId;@Value("${tencent.cos.secret-key}")private String secretKey;@Value("${tencent.cos.region}")private String region;@Beanpublic COSClient cosClient() {COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);Region cosRegion = new Region(region);return new COSClient(cred, cosRegion);}
}
4. 文件上傳接口
(1)普通上傳
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.PutObjectRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.UUID;@RestController
@RequestMapping("/api/upload")
public class UploadController {@Autowiredprivate COSClient cosClient;@Value("${tencent.cos.bucket-name}")private String bucketName;@PostMapping("/simple")public String simpleUpload(@RequestParam("file") MultipartFile file) {try {String remoteFileName = "uploads/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();InputStream inputStream = file.getInputStream();PutObjectRequest request = new PutObjectRequest(bucketName, remoteFileName, inputStream, null);cosClient.putObject(request);return "https://" + bucketName + ".cos." + cosClient.getClientConfig().getRegion().getName() + ".myqcloud.com/" + remoteFileName;} catch (Exception e) {return "上傳失敗: " + e.getMessage();}}
}
(2)分片上傳接口
① 初始化分片上傳
@PostMapping("/init")
public String initMultipartUpload(@RequestParam String fileName) {try {InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileName);return cosClient.initiateMultipartUpload(request).getUploadId();} catch (Exception e) {return "初始化失敗: " + e.getMessage();}
}
② 上傳分片
@PostMapping("/part")
public String uploadPart(@RequestParam("file") MultipartFile file,@RequestParam("uploadId") String uploadId,@RequestParam("partNumber") int partNumber,@RequestParam("fileName") String fileName) {try {UploadPartRequest request = new UploadPartRequest().withBucketName(bucketName).withKey(fileName).withUploadId(uploadId).withPartNumber(partNumber).withInputStream(file.getInputStream()).withPartSize(file.getSize());return cosClient.uploadPart(request).getETag(); // 返回 ETag} catch (Exception e) {return "分片上傳失敗: " + e.getMessage();}
}
③ 合并分片
@PostMapping("/complete")
public String completeMultipartUpload(@RequestParam("fileName") String fileName,@RequestParam("uploadId") String uploadId,@RequestParam("partETags") List<String> partETags) {try {List<PartETag> partETagList = partETags.stream().map(etag -> new PartETag(partETags.indexOf(etag) + 1, etag)).toList();CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, fileName, uploadId, partETagList);cosClient.completeMultipartUpload(request);return "https://" + bucketName + ".cos." + cosClient.getClientConfig().getRegion().getName() + ".myqcloud.com/" + fileName;} catch (Exception e) {return "合并失敗: " + e.getMessage();}
}
四、前端(Vue2)實現
1. 安裝依賴
npm install axios
2. 分片上傳邏輯
<template><div><input type="file" @change="handleFileChange" /><button @click="uploadFile">上傳</button><div>上傳進度: {{ progress }}%</div></div>
</template><script>
import axios from 'axios';export default {data() {return {file: null,uploadId: '',chunkSize: 5 * 1024 * 1024, // 5MBprogress: 0,uploadedChunks: [], // 已上傳的分片索引};},methods: {handleFileChange(event) {this.file = event.target.files[0];this.uploadedChunks = [];this.progress = 0;},async uploadFile() {if (!this.file) {alert("請選擇文件");return;}// 1. 初始化分片上傳const initRes = await axios.post('/api/upload/init', {fileName: this.file.name,});this.uploadId = initRes.data;// 2. 并發上傳分片const totalChunks = Math.ceil(this.file.size / this.chunkSize);const promises = [];for (let i = 0; i < totalChunks; i++) {const start = i * this.chunkSize;const end = Math.min(start + this.chunkSize, this.file.size);if (this.uploadedChunks.includes(i)) continue; // 跳過已上傳分片const chunk = this.file.slice(start, end);const formData = new FormData();formData.append('file', chunk);formData.append('uploadId', this.uploadId);formData.append('partNumber', i + 1);formData.append('fileName', this.file.name);const promise = axios.post('/api/upload/part', formData, {onUploadProgress: (progressEvent) => {const percent = Math.round(((this.uploadedChunks.length * 100) / totalChunks) +((progressEvent.loaded / progressEvent.total) * 100 / totalChunks));this.progress = percent;},});promises.push(promise.then(() => {this.uploadedChunks.push(i); // 標記為已上傳}));}// 并發上傳await Promise.all(promises);// 3. 合并分片const completeRes = await axios.post('/api/upload/complete', {fileName: this.file.name,uploadId: this.uploadId,partETags: [], // 后端應返回每個分片的 ETag});alert("上傳成功: " + completeRes.data);},},
};
</script>
五、注意事項與優化
1. 分片大小限制
- 騰訊云要求?單個分片最小 1MB,最大 5GB。
- 推薦設置?
chunkSize = 5 * 1024 * 1024
(5MB)。
2. 并發上傳優化
- 使用?
Promise.all
?實現并發上傳,提升上傳效率。 - 可設置最大并發數,避免過多請求導致服務器壓力過大。
3. 斷點續傳支持
- 通過?
this.uploadedChunks
?記錄已上傳分片索引。 - 重啟上傳時跳過已上傳部分,實現斷點續傳。
4. 安全性增強
- 禁止前端暴露 SecretId/SecretKey。
- 建議使用?STS 臨時密鑰?或?后端代理上傳。
- 后端可封裝上傳邏輯,前端僅調用后端接口上傳文件。
- 使用騰訊云 STS 獲取臨時密鑰,設置訪問權限和有效期。
六、總結
本教程完整實現了基于 Spring Boot + Vue2 的騰訊云 COS 文件上傳功能,支持:
- 普通上傳
- 大文件分片上傳(支持并發、斷點續傳)
- 安全性增強(密鑰不暴露)
- 跨域規則配置(CORS)
可根據實際業務需求進一步擴展,如添加上傳進度持久化、上傳失敗重試機制等。