Implement Chunked Large File Upload with Tencent Cloud COS, Vue2 & Spring Boot
This guide demonstrates how to configure Tencent Cloud COS for both simple and multipart large‑file uploads in a front‑end/back‑end separated architecture, using Vue2 on the client side and Spring Boot with YML configuration on the server, covering bucket setup, security, CORS, concurrency, and resumable upload techniques.
1. Project Goal
Implement large file chunked upload and normal file upload based on Tencent Cloud COS, using a front‑back separation architecture with Vue2 + Spring Boot + YML configuration, covering the following points:
Chunk size limit
Concurrent upload optimization
Resumable upload support
Security enhancement (avoid exposing secret keys)
CORS configuration
2. Tencent Cloud COS Basic Configuration
1. Create Bucket
Login to Tencent Cloud console → Object Storage COS → Create bucket:
Bucket name: your-bucket-name-1250000000 Region: ap-beijing (choose as needed)
Permission: Private read/write
2. Obtain API Keys
Go to API key management page and create or use existing SecretId/SecretKey.
✅ Security tip: Do not use SecretId/SecretKey directly in the front end; use a back‑end proxy or STS temporary credentials.
3. Set CORS Rules
Navigate to Permission Management → CORS Rules and add:
{
"allowedOrigin": ["*"],
"allowedMethod": ["GET","POST","PUT","HEAD"],
"allowedHeader": ["*"],
"exposeHeader": [],
"maxAgeSeconds": 3000
}3. Backend (Spring Boot) Implementation
1. Dependency Configuration
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Tencent Cloud COS SDK -->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.2.4</version>
</dependency>
<!-- Utility -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>2. Configure COS in application.yml
tencent:
cos:
secret-id: YOUR_SECRET_ID
secret-key: YOUR_SECRET_KEY
region: ap-beijing
bucket-name: your-bucket-name-12500000003. Initialize COS Client
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;
@Bean
public COSClient cosClient() {
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
Region cosRegion = new Region(region);
return new COSClient(cred, cosRegion);
}
}4. File Upload API
1) Simple Upload
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 {
@Autowired
private 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 "Upload failed: " + e.getMessage();
}
}
}2) Multipart Upload
① Initialize multipart upload
@PostMapping("/init")
public String initMultipartUpload(@RequestParam String fileName) {
try {
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileName);
return cosClient.initiateMultipartUpload(request).getUploadId();
} catch (Exception e) {
return "Initialization failed: " + e.getMessage();
}
}② Upload part
@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();
} catch (Exception e) {
return "Part upload failed: " + e.getMessage();
}
}③ Complete multipart upload
@PostMapping("/complete")
public String completeMultipartUpload(@RequestParam("fileName") String fileName,
@RequestParam("uploadId") String uploadId,
@RequestParam 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 "Merge failed: " + e.getMessage();
}
}4. Frontend (Vue2) Implementation
1. Install Dependency
npm install axios2. Chunked Upload Logic
<template>
<div>
<input type="file" @change="handleFileChange"/>
<button @click="uploadFile">Upload</button>
<div>Upload progress: {{ progress }}%</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
file: null,
uploadId: '',
chunkSize: 5 * 1024 * 1024,
progress: 0,
uploadedChunks: []
};
},
methods: {
handleFileChange(event) {
this.file = event.target.files[0];
this.uploadedChunks = [];
this.progress = 0;
},
async uploadFile() {
if (!this.file) {
alert('Please select a file');
return;
}
const initRes = await axios.post('/api/upload/init', { fileName: this.file.name });
this.uploadId = initRes.data;
const totalChunks = Math.ceil(this.file.size / this.chunkSize);
const promises = [];
for (let i = 0; i < totalChunks; i++) {
if (this.uploadedChunks.includes(i)) continue;
const start = i * this.chunkSize;
const end = Math.min(start + this.chunkSize, this.file.size);
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: (e) => {
const percent = Math.round(((this.uploadedChunks.length * 100) / totalChunks) + ((e.loaded / e.total) * 100 / totalChunks));
this.progress = percent;
}
}).then(() => {
this.uploadedChunks.push(i);
});
promises.push(promise);
}
await Promise.all(promises);
const completeRes = await axios.post('/api/upload/complete', {
fileName: this.file.name,
uploadId: this.uploadId,
partETags: [] // backend should return ETags
});
alert('Upload successful: ' + completeRes.data);
}
}
};
</script>5. Notes and Optimizations
1. Chunk Size Limits
Tencent Cloud requires each part to be at least 1 MB and at most 5 GB.
Recommended setting: chunkSize = 5 * 1024 * 1024 (5 MB).
2. Concurrent Upload Optimization
Use Promise.all to upload parts concurrently and improve efficiency.
Limit maximum concurrency to avoid excessive server load.
3. Resumable Upload Support
Track uploaded parts with this.uploadedChunks to skip already uploaded chunks.
On restart, continue from the last successful part.
4. Security Enhancements
Never expose SecretId/SecretKey on the front end.
Prefer STS temporary credentials or back‑end proxy for uploading.
6. Summary
This tutorial fully implements Tencent Cloud COS file upload with Spring Boot and Vue2, supporting simple upload, large‑file multipart upload with concurrency and resumable capabilities, enhanced security, and CORS configuration.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
