一、项目目标

实现基于腾讯云 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_ID
    secret-key: YOUR_SECRET_KEY
    region: ap-beijing
    bucket-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
publicclassCosConfig {

    @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() {
        COSCredentialscred=newBasicCOSCredentials(secretId, secretKey);
        RegioncosRegion=newRegion(region);
        returnnewCOSClient(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")
publicclassUploadController {

    @Autowired
    private COSClient cosClient;

    @Value("${tencent.cos.bucket-name}")
    private String bucketName;

    @PostMapping("/simple")
    public String simpleUpload(@RequestParam("file") MultipartFile file) {
        try {
            StringremoteFileName="uploads/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();
            InputStreaminputStream= file.getInputStream();

            PutObjectRequestrequest=newPutObjectRequest(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 {
        UploadPartRequestrequest=newUploadPartRequest()
                .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 -> newPartETag(partETags.indexOf(etag) + 1, etag))
                .toList();

        CompleteMultipartUploadRequestrequest=newCompleteMultipartUploadRequest(
                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';

exportdefault {
data() {
    return {
      file: null,
      uploadId: '',
      chunkSize: 5 * 1024 * 1024, // 5MB
      progress: 0,
      uploadedChunks: [], // 已上传的分片索引
    };
  },
methods: {
    handleFileChange(event) {
      this.file = event.target.files[0];
      this.uploadedChunks = [];
      this.progress = 0;
    },
    asyncuploadFile() {
      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 = newFormData();
        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); // 标记为已上传
        }));
      }

      // 并发上传
      awaitPromise.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)

可根据实际业务需求进一步扩展,如添加上传进度持久化、上传失败重试机制等。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐