腾讯云对象存储COS 通过签名上传文件generatePresignedUrl()方法实践

对象存储COS 通过签名上传文件实践

使用COS上传文件可以有多种方式

  • 使用secretId、secretKey方式上传
  • 使用临时密钥上传
  • 使用签名上传

今天来分享下使用签名方式上传文件的实践,官方文档如下
腾讯云请求签名文档

腾讯云COS存储支持通过签名方式上传文件访问时只需要带有sdk生成的签名即可上传文件,我使用的是签名 URL的方式,使用的是java sdk

其实就是腾讯云COS sdk中提供了一个类COSClient,通过使用类中的generatePresignedUrl()方法,通过指定参数,会生成一个可以访问的url,url中有名为sign的param参数,如下(只是样例)
https://bucket-123456.cos.ap-beijing.myqcloud.com/test/test/test/test6.txt
?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDNFKHNM9udHmOvT%26q-sign-time%3D1717058465%3B1717061400%26q-key-time%3D1717058465%3B1717061400%26q-header-list%3Dcontent-md5%3Bcontent-type%26q-url-param-list%3D%26q-signature%3D91cc03c73bc6c64002f5
直接访问这个url就可以上传文件

  • 在生成用于上传的签名链接时,还可以指定 Content-Type 或 Content-MD5 等头部,以便限制上传的媒体类型或限制上传的内容必须为指定内容

直接上代码

使用的依赖是

<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>cos_api</artifactId>
    <version>5.6.18</version>
</dependency>

主要用到如下的类

import com.qcloud.cos.COSClient;

该方法

public URL generatePresignedUrl(GeneratePresignedUrlRequest req) throws CosClientException{…}

首先你需要初始化COSClient

定义一个配置类保存COS相关配置

@Configuration
@Data
public class OssConfig {

    @Value("${cos.secret-id}")
    private String secretId;

    @Value("${cos.secret-key}")
    private String secretKey;

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

    @Value("${cos.bucket-region}")
    private String bucketRegion;

    @Value("${cos.url-domain}")
    private String urlDomain;
}

初始化COSClient

// 我这里使用@Configuration+@Bean注解在服务启动时初始化
@Configuration
public class DomainServiceImplConfig {

    @Bean
    public COSClient cosClient(OssConfig ossConfig) {
        return generateCosClient(ossConfig.getSecretId(), ossConfig.getSecretKey(), ossConfig.getBucketRegion());
    }

    private COSClient generateCosClient(String secretId, String secretKey, String bucketRegion) {
        //1.初始化用户身份信息
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        //2.设置bucket区域
        Region region = new Region(bucketRegion);
        ClientConfig clientConfig = new ClientConfig(region);
        clientConfig.setConnectionTimeout(ObjectUploadConstants.COS_TIME_OUT);
        clientConfig.setConnectionRequestTimeout(ObjectUploadConstants.COS_TIME_OUT);
        //3.生成cos客户端
        return new COSClient(cred, clientConfig);
    }
}

定义一个请求体

@Data
public class PrivateBucketUploadSignBo {

	// 用户自己指定文件要存储的cosKey位置
    private String cosKey;

	// 生成的签名过期时间
    private Date expireTime;

	// 使用签名上传文件时的请求方式 POST还是PUT
	// 这里有个坑 腾讯云当前只支持通过PUT方式访问
    private String method;

	// 用户自己计算的Md5值,可以为空
    private String contentMd5;

	// 用户指定的MIME类型可以为空
    private String contentType;

}

生成签名的逻辑如下


@Resource
private OssConfig ossConfig;

public String getBucketUploadSign(PrivateBucketUploadSignBo bo) {
    String bucketName = ossConfig.getBucketName();
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, bo.getCosKey(), bo.getMethod());
    request.setExpiration(bo.getExpireTime());
    // 该字段为非必填,主要是用来限制文件上传类型,用户不填即不开启
    if (StringUtils.isNotBlank(bo.getContentType())) {
        request.setContentType(bo.getContentType());
    }
    // 该字段为非必填,用来校验文件完整性,用户不填即不开启
    if (StringUtils.isNotBlank(bo.getContentMd5())) {
        request.setContentMd5(bo.getContentMd5());
    }
    URL url = cosClient.generatePresignedUrl(request);
    return url.toString();
}

补充说明

计算Md5的方法

该主要功能就是保证内容的完整,如果网络传输过程中有内容丢失,那么请求签名时的
最终计算得到的Md5形似 UV9RaUC3bem55119dY/PGA==

Java

public class MD5AndBase64Example {

    public static void main(String[] args) {
        String filePath = "D:\\20240530_092350_434_1_aplogcat.txt.zst"; // 请替换为你的文件路径
        String content = null;
        try {
            List<String> lines = Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8);
            content = String.join(System.lineSeparator(), lines);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String objectBody = content;
        try {
            // 计算MD5哈希值  
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(objectBody.getBytes("UTF-8"));

            // 将哈希值转换为十六进制字符串  
            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b & 0xff));
            }

            // 将哈希值的字节数组进行Base64编码  
            String base64Hash = Base64.getEncoder().encodeToString(hashBytes);

            // 打印Base64编码的哈希值  
            System.out.println("Base64 Hash: " + base64Hash);

        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            // MD5算法通常总是可用的,但出于完整性考虑,我们仍然捕获异常  
            e.printStackTrace();
        }
    }
}

自测

首先明确如果在生成签名时,自己设置了
contentType 该参数如果设置了,之后上传时使用的Content-Type需要和签名时保持一致
contentMd5
该参数如果设置了,之后

  1. 获取签名时的contentMd5参数
  2. 上传时请求头的Content-MD5
  3. 上传时文件计算得到的实际MD5
    三者需要保持一致

生成签名后会返回一个带sign参数的url链接
例如
https://bucket-123456.cos.ap-beijing.myqcloud.com/test/test/test/test6.txt
?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDNFKHNM9udHmOvT%26q-sign-time%3D1717058465%3B1717061400%26q-key-time%3D1717058465%3B1717061400%26q-header-list%3Dcontent-md5%3Bcontent-type%26q-url-param-list%3D%26q-signature%3D91cc03c73bc6c64002f5

直接使用在PostMan中发起PUT请求即可

如果生成签名时使用了这两个参数,那么请求头中这两个参数需要保持一致
在这里插入图片描述
问题来了文件在哪里传呢
在请求的Body中binary类型
直接选择文件即可在这里插入图片描述
bingo!响应200,成功,再去COSBrowser中查查看,也确实有了
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值