对象存储

项目介绍

针对各个公有云和私有云提供功能不同,为了使上层开发与具体应用解耦,所以提供SDK适配各个云厂商,供上层服务调用。可以通过简单的切换配置文件,达到切换不同厂商的功能。

功能介绍

ObjectStorage 是为了适配多云的对象存储而开发的 SDK,用于支持产品在多个云的环境部署运行。产品可以通过简单的修改配置,不用修改代码就能完成在多云之间的平滑部署迁移。

  • 适配了阿里云的 OSS,华为云的 OBS ,腾讯云的COS,以及私有化环境下的 minioceph以及青云。
  • 支持对象存储的各种操作:上传文件,下载文件,签名直传,缩略图,视频截帧等。
  • 支持通过临时授权STS的方式获取临时密钥,进行对象存储的访问。

基于ObjectStorage提供的便捷,为了在使用上可以更加方便,我们提供了object-storage-spring-boot-starter,其内部是基于ObjectStorage的实现,为上层提供了自动配置的功能,也就是starter包。

快速接入

1.配置settings.xml私仓地址

<!--云中立私仓-->
<repository>
    <id>multicloud-release</id>
    <name>multicloud-release</name>
    <url>https://packages.glodon.com/artifactory/maven-multicloud-release</url>
</repository>
<repository>
    <id>multicloud-snapshot</id>
    <name>multicloud-snapshot</name>
    <url>https://packages.glodon.com/artifactory/maven-multicloud-snapshot</url>
</repository>
    

2.项目中添加 pom 依赖(内源版本,目前尚未发布,如需接入请联系郭锁奇,域账号guosq-a)

<dependency>
    <groupId>com.glodon.paas.foundation</groupId>
    <artifactId>object-storage-spring-boot-starter</artifactId>
     <version>1.3.13.SB1_5</version>
</dependency>
    

如果结合spring-cloud-glodon使用,则通过引入spring-cloud-glodon-dependencies后管理依赖版本即可

<dependency>
    <groupId>com.glodon.paas.foundation</groupId>
    <artifactId>object-storage-starter-spring-boot-starter</artifactId>
</dependency>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.glodon.cloud</groupId>
            <artifactId>spring-cloud-glodon-dependencies</artifactId>
            <version>2.3.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
    

3.配置yaml

object-storage:
	protocol: S3_HW #可选项 OSS、S3_HW、S3_COS、S3_AWS、S3_AWS_V4、S3_MINIO、S3_CEPH、S3_QY、S3
    endPoint: your.end-point
    accessKeyId: your.access.key.id
    accessKeySecret: your.access.key.secret
    # 新增可选配置项
    region: your-region
    pathStyleAccess: true/false # 是否强制开启路径形式的资源访问
    externalEndpoint: your-external-endpoint # 是否使用对外的endpoint,默认false。在对象存储的某些操作中,例如获得签名URL时,需要给用户对外的endpoint
    maxConnections: # 连接数
    connectionTimeout: # 连接超时时间
    socketTimeout: # socket超时时间
    # 废弃配置项: 老版本的图片处理和视频处理等功能需要配置云厂商,当前新版本无需配置即可使用
    provider: ali/huawei
    

配置项说明:

/**
     * 是否强制开启路径形式的资源访问
     *
     * (指定为Boolean.TRUE,那么使用endpoint/bucket的方式来访问)
     * (指定为Boolean.FALSE,那么使用bucket.endpoint的方式来访问)
     * (不指定则为null,使用OSS或者S3的默认方式:
     *      OSS默认采用bucket.endpoint;
     *      S3默认对于ip格式的endpoint和非合法DNS格式的bucket采用endpoint/bucket,
     *          而其他情况使用bucket.endpoint;
     *      S3_HW:与S3默认情况相同;
     *      S3_QY:与S3默认情况相同;
     *      S3_CEPH:默认使用endpoint/bucket方式访问
     *      S3_MINIO: 默认使用endpoint/bucket方式访问;
     *      )
     *
     *  默认值大多数情况下足够使用,绝大多数情况不需要指定这个参数
     */
private Boolean pathStyleAccess;



/**
	* 该配置项当前主要针对,签名直传功能的接口,可以通过externalEndpoint控制获取到的host是内网还是外网
	*/
private String externalEndpoint;
    

4.注入对象

配置完成后,就可以在代码中注入ObjectClient来使用。

@Autowired
ObjectClient objectClient;
    

5.常用操作

5.1 文件上传下载

// 上传文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.put(objectBasicInfo, file);

// 分片上传文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.multiPartPut(objectBasicInfo, file, partSize);

//追加上传文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.appendPut(objectBasicInfo, file, position, messageDigestSerializer);

// 下载文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.get(objectBasicInfo, file);

//复制文件
objectClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey) 

    

5.2 获取签名URL

ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
String strUrl = objectClient.getSignedURL(objectBasicInfo, 600, "", SignedUrlBehavior.DOWNLOAD, null).toString();// 过期时间设置成600s
    

5.3 图片操作

// 1.先定义 DataProcessor
DataProcessor processor = new DataProcessor(DataProcessor.Type.IMAGE, Collections.singletonList("resize,w_100,h_100"));
// 2.调用下面两个方法之一
ObjectClient.getSignedURL(ObjectBasicInfo objectBasicInfo, int expiredTime, String fileName,SignedUrlBehavior behavior, DataProcessor processor);
RawClient.getSignedURL(SignedURLRequest signedURLRequest);
    

针对华为云和阿里OSS,图片处理是全功能支持的。

针对ceph、minIO、QingYunS3,图片处理功能是在object-storage中自己实现的。实现方式是基于github上的开源项目thumbnailator:前往GitHub查看

仅支持了resize 操作,format操作。resize 功能与阿里云保持一致,但是调用resize,允许放大和缩小(没有实现limit_0和limit_1功能)。

在一个action中,参数优先级[w,h]>l>s>p,高优先级的参数将覆盖低优先级的参数操作,与出现的顺序无关,同一个参数出现多次,后面的会覆盖前面的,参数m没有优先级。

原理:先将图片下载下来,然后使用工具处理之后,将处理后的图片上传至同一个bucket下的ImageProcessTempFolder文件夹内。文件名字为:etag+actions+format

5.4 视频截帧

// 1.定义 processor
DataProcessor processor = new DataProcessor(DataProcessor.Type.VIDEO,
                Collections.singletonList("snapshot,t_5000,f_jpg,w_800,h_600,m_fast"));
// 2.调用下面两个方法之一获取截图
ObjectClient.getSignedURL(ObjectBasicInfo objectBasicInfo, int expiredTime, String fileName,SignedUrlBehavior behavior, DataProcessor processor));

RawClient.getSignedURL(SignedURLRequest signedURLRequest);
 
    
参数 描述 取值范围
t 截图时间 单位ms,[0,视频时长]
w 截图宽度,如果指定为0则按照比例自动计算 像素值:[0,视频宽度]
h 截图高度,如果指定为0则按照比例自动计算,如果w和h都为0则输出为原视频宽高 像素值:[0,视频高度]
m 截图模式,不指定则为默认模式,根据时间精确截图,如果指定为fast则截取该时间点之前的最近的一个关键帧 枚举值:fast
f 输出图片格式 枚举值:jpg、png

5.5 签名直传

PostPolicyRequest postPolicyRequest = new PostPolicyRequest(600, 1000L, "your-bucket");
PostPolicyInfo postPolicyInfo = objectClient.generatePostPolicy(postPolicyRequest);
    

拿到 postPolicyInfo 后,浏览器发起的请求应该如下

 curl -X POST ${info.host} \
  -H 'content-type: multipart/form-data' \
  -F 'key=ABCD.file' \
  -F policy=${info.encodedPolicy} \
  -F ${info.accessIdName}=${info.accessId} \
  -F callback=${info.callback} \
  -F signature=${info.postSignature} \
  -F success_action_status=200 \
  -F 'file=@/your/path/ABCD.file' 
    
5.5.1 示例

服务端需要提供获取签名信息的接口(本示例以java为例)

@RestController
@CrossOrigin(allowCredentials = "true")
public class ObjectStorageController {

    @Autowired
    private ObjectClient objectClient;

    @GetMapping("signature")
    public String getSignature(){
        PostPolicyRequest postPolicyRequest = new PostPolicyRequest(600, 10 * 1024 * 1024L, bucketName);
        PostPolicyInfo postPolicyInfo = objectClient.generatePostPolicy(postPolicyRequest);
        return JSONObject.toJSONString(postPolicyInfo);
    }
}
    

前端html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>OBS web直传</title>
</head>

<body>
<h2 align="center">web直传</h2>
<div>
    <p align="center">
        <input type="file" id="post_file" name="post_file">
    </p>
    <p align="center">
        <button type="submit" value="上传" class="btn btn-success" onclick="postFile()">上传</button>
    </p>
</div>
</body>

<script type="text/javascript">
    function postFile() {
        // 获取签名的服务端地址
        const signUrl = "http://localhost:9000/signature";
        // 1.获取文件
        const resultFile = document.getElementById("post_file").files[0];
        // 2.获取签名 result, 结构如下
        /**
         {
          "accessId": "XXXXXXX",
          "accessIdName": "OSSAccessKeyId",
          "contentDisposition": "inline/attachment",
          "contentType": "application/octet-stream",
          "encodedPolicy": "XXXXXX",
          "expireTimeSeconds": 1603784561,
          "host": "XXXXXX",
          "postPolicy": "{expiration:xxxxxx,conditions:[[content-length-range,0,10485760],{bucket:xxxxxx},{success_action_status:200},{Content-Disposition:xxxxxx},{Content-Type:xxxxxx},[starts-with,$key,xxxxxx]]}",
          "postSignature": "xxxxxxx"
        }
         */
        const result = getSignature(signUrl);
        // 3.解析从服务端获取到的签名和策略相关的信息
        const policy = resolvePostPolicy(result.postPolicy);
        // 4.上传 (注意设置 isS3 参数)
        let uploadResult = postObjectByAjax(resultFile, result.accessId, result.encodedPolicy,
            result.postSignature, result.host, policy.contentType, policy.contentDisposition, policy.keyPrefix, false);
        if (uploadResult === true) {
            alert("上传成功")
        } else {
            alert("上传失败")
        }
    }
</script>
<script src="https://yzl-oss-test.oss-cn-beijing.aliyuncs.com/objectstorage-web/objectstorage.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">

</html>
    

注意

上述html中https://yzl-oss-test.oss-cn-beijing.aliyuncs.com/objectstorage-web/objectstorage.js是云中立提供的objectstorage.js下载地址,可以直接引用;若需要修改,也可以从下方示例下载链接中下载后修改使用。

objectstorage.js文件

/**
 * @Author: baijd-a
 * @Date: 2020-10-26 15:58:29
 * @LastEditTime: 2020-10-26 15:58:29
 * @LastEditors: baijd-a
 * @Description: 采用云中立平台的对象存储适配,下面代码演示了前端如何采用签名直传的方式上传文件到 OSS、S3
 * 针对请求方式可采用 ajax axios
 */

/**
 * 根据url从服务端获取签名直传的签名相关信息
 * @param url
 * @returns 签名相关信息
 */
function getSignature(url) {
    let result = null;
    $.ajax({
        url: url,
        type: "get",
        async: false,
        success: function (data) {
            result = JSON.parse(data);
        }
    });
    return result;
}

/**
 * 通过 Ajax 上传文件到云服务
 *
 * 注意:
 *      请求时 FormData 参数中的 Content-Type, Content-Disposition, keyPrefix 需要和后端返回的策略中保持一致
 *
 * @param file 文件
 * @param accessId AK
 * @param policy 上传策略 base64值
 * @param signature 签名
 * @param host 上传的host
 * @param contentType 上传的Content-Type ===> 从服务端获取到的 Policy 中的值
 * @param contentDisposition 展示形式:内联(inline),附件下载(attachment; filename="xxx") ===> 从服务端获取到的 Policy 中的值
 * @param objectKeyPrefix 上传的key前缀
 * @param isS3 是否是S3服务[华为云、腾讯云、MINIO、CEPH、AWS]
 */
function postObjectByAjax(file, accessId, policy, signature, host, contentType, contentDisposition, objectKeyPrefix, isS3) {
    let form = new FormData();
    if (isS3) {
        form.append('AWSAccessKeyId', accessId); // S3 的 accessID; 若是上传到 S3 采用这个参数
    } else {
        form.append('OSSAccessKeyId', accessId);  // OSS 的 accessID; 若是上传到 OSS 采用这个参数
    }
    form.append('policy', policy);
    form.append('signature', signature);
    if (contentType !== null && contentType !== '') {
        form.append("Content-Type", contentType);
    }
    if (contentDisposition !== null && contentDisposition !== '') {
        form.append("Content-Disposition", contentDisposition)
    }
    if (objectKeyPrefix == null) {
        objectKeyPrefix = '';
    } else if (objectKeyPrefix !== '' && !objectKeyPrefix.endsWith("/")) {
        objectKeyPrefix += "/";
    }
    form.append('key', objectKeyPrefix + file.name);  // key: 文件上传的完整路径 若有目录含有目录
    form.append('success_action_status', 200); // 文件上传成功后返回的状态
    form.append('file', file);

    return _ajaxPostObject(host, form);
}

function _ajaxPostObject(url, formData) {
    var result = false;
    $.ajax({
        type: "POST",
        url: url,
        data: formData,
        processData: false,
        cache: false, // 设置为false将不会从浏览器缓存中加载请求信息
        async: false, // 发送同步请求
        contentType: false, // 避免服务器不能正常解析文件
        // dataType: 'JSONP', // jsonp只能提供get请求; 不涉及跨域, 写json即可
        success: function (data) {
            result = true;
        }
    });
    return result;
}

/**
 * 通过 Axios 上传文件到云服务
 *
 * 注意:
 *      请求时 FormData 参数中的 Content-Type, Content-Disposition, keyPrefix需要和后端返回的策略中保持一致
 *
 * @param file 文件
 * @param accessId AK
 * @param policy 上传策略 base64值
 * @param signature 签名
 * @param host 上传的host
 * @param contentType 上传的Content-Type  ===> 从服务端获取到的 Policy 中的值
 * @param contentDisposition 展示形式:内联(inline),附件下载(attachment; filename="xxx") ===> 从服务端获取到的 Policy 中的值
 * @param objectKeyPrefix 上传的key前缀
 * @param isS3 是否是S3服务[华为云、腾讯云、MINIO、CEPH、AWS]
 */
function postObjectByAxios(file, accessId, policy, signature, host, contentType, contentDisposition, objectKeyPrefix, isS3) {
    let form = new FormData();
    if (isS3) {
        form.append('AWSAccessKeyId', accessId); // S3 的 accessID; 若是上传到 S3 采用这个参数
    } else {
        form.append('OSSAccessKeyId', accessId);  // OSS 的 accessID; 若是上传到OSS 采用这个参数
    }
    form.append('policy', policy);
    form.append('signature', signature);
    form.append('signature', signature);
    if (contentType !== null && contentType !== '') {
        form.append("Content-Type", contentType);
    }
    if (contentDisposition !== null && contentDisposition !== '') {
        form.append("Content-Disposition", contentDisposition)
    }
    if (objectKeyPrefix == null) {
        objectKeyPrefix = '';
    } else if (objectKeyPrefix !== '' && !objectKeyPrefix.endsWith("/")) {
        objectKeyPrefix += "/";
    }
    form.append('key', objectKeyPrefix + file.name);  // key: 文件上传的完整路径 若有目录含有目录
    form.append('success_action_status', 200); // 文件上传成功后返回的状态,默认204
    form.append('file', file);  // 文件流

    let config = {
        header: {
            'Content-Type': 'multipart/form-data;',
        }
    };
    axios.post(host, form, config)
        .then(res => {
            console.log('上传成功');
        })
        .catch(error => {
            console.log('上传失败');
            console.log(error)
        });
}

/**
 * 判断对象是否为数组
 * @param o 要判断的对象
 * @returns {boolean} 判断结果
 */
function isArray(o) {
    return Object.prototype.toString.call(o) === '[object Array]';
}

/**
 * 将后端返回的结构中的策略 Policy json 进行解析
 * @param postPolicyJson Policy json
 * @returns {{contentDisposition: string, contentType: string, keyPrefix: string}}
 */
function resolvePostPolicy(postPolicyJson) {
    // 解析从服务端获取到的签名和策略相关的信息
    let contentDisposition = '';
    let contentType = '';
    let keyPrefix = '';

    const postPolicy = JSON.parse(postPolicyJson);
    const conditions = postPolicy.conditions;
    for (let i = 0; i < conditions.length; i++) {
        const condition = conditions[i];
        if (isArray(condition) && condition[0] === 'starts-with') {
            keyPrefix = condition[2];
        } else {
            if (condition['Content-Type'] !== undefined) {
                contentType = condition['Content-Type'];
            }
            if (condition['Content-Disposition'] !== undefined) {
                contentDisposition = condition['Content-Disposition'];
            }
        }
    }
    return {
        contentType: contentType,
        contentDisposition: contentDisposition,
        keyPrefix: keyPrefix
    }
}
    

服务端http://localhost:9000/signature返回结果:

{
    "accessId": "xxxxx",
    "accessIdName": "OSSAccessKeyId",
    "encodedPolicy": "xxxxxxx",
    "expireTimeSeconds": 1603790181,
    "host": "https://xxxxxx.com",
    "postPolicy": "{expiration:xxxxxx,conditions:[[content-length-range,0,10485760],{bucket:xxxxxx},{success_action_status:200},{Content-Disposition:xxxxxx},{Content-Type:xxxxxx},[starts-with,$key,xxxxxx]]}",
    "postSignature": "xxxxxx"
}
    

阿里云上传结果:

General
    Request URL: https://xxxxxx.com/
    Request Method: POST
    Status Code: 200 OK
    Remote Address: xxx.xxx.xxx.xxx
    Referrer Policy: strict-origin-when-cross-origin


Form Data
    OSSAccessKeyId: xxxxxx
    policy: xxxxxx
    key: test1/xxxxxx.txt
    success_action_status: 200
    file: (binary)
    
5.5.2 示例下载链接

示例下载链接

5.6 sts临时授权访问对象存储

STS(Security Token Service),可以进行临时授权访问。通过STS,您可以为第三方应用或子用户(即用户身份由您自己管理的用户)颁发一个自定义时效和权限的访问凭证。

阿里云 STS

华为云 STS

腾讯云 STS

亚马逊 STS

注意:由于临时授权访问密钥需要使用子用户的AK,SK进行API调用,所以如果没有子用户,请自建子用户,且分配S3操作权限。参考官网

MINIO STS

环境搭建步骤:根据minio光网介绍,我们可以通过AssumeRole方式获取临时访问密钥,其余实现方式参考Minio官网

注意:由于为临时授权访问密钥,所以此处需要使用子用户的AK,SK进行API使用,如果没有,请自建子用户。

5.6.1 阿里云示例

yaml配置

object-storage:
  end-point: https://your-region.aliyuncs.com
sts:
  protocol: OSS
  # sts-endpoint: # 阿里云有默认的stsEndpoint,也可以自己指定
  accessKeyId: xxxxxx
  accessKeySecret: xxxxxx
  roleArn: acs:ram::xxxxxx:role/xxxxxx # roleArn配置,STS获取临时授权需要用到
    

上述配置肿的sts,已经配置了一个sts的客户端stsClient,我们可以直接注入即可

@Autowired
private StsClient stsClient;
    

然后我们需要根据stsClient获取临时密钥,用临时密钥构造一个对象存储的客户端注入spring容器使用

此处以阿里云为例,指定特定bucket下的resource权限*

@Bean
public ObjectClient objectClient() {
    final String[] actions = {"oss:*"};
    final String[] resources = {"acs:oss:*:*:" + your-bucketName, "acs:oss:*:*:" + your-bucketName + "/*"};
	// 根据上述指定的 actions和 resources,构造请求策略
    StsRequestPolicyStatement statement = new StsRequestPolicyStatement.Builder()
        .action(actions)
        .resource(resources)
        .build();
    StsRequestPolicy stsRequestPolicy = new StsRequestPolicy.Builder()
        .statement(new StsRequestPolicyStatement[]{statement})
        .build();
    // 根据构造的请求策略和临时密钥有效时常,获取临时密钥
    StsResponse stsResponse = stsClient.getStsResponse(stsRequestPolicy, 15 * 60);
    System.out.println(stsResponse.toString());
	// 根据获取的临时密钥构造ObjectClient的配置
    RawClientConfig.Builder configBuilder = RawClientConfig.builder()
        .endpoint(endpoint)
        .accessKeyId(stsResponse.getAccessKeyId())
        .secretAccessKey(stsResponse.getAccessKeySecret())
        .securityToken(stsResponse.getSecurityToken());
    if (StringUtils.isNotBlank(region)) {
        configBuilder.region(region);
    }
	// 根据配置构造ObjectClient,注入spring容器
    return new ObjectClient(configBuilder.build(), ClientType.valueOf(protocol.toUpperCase()),
                            null, null);
}
    

这样,就可以在您的应用中使用上述的ObjectClient

@Autowired
private ObjectClient objectClient;
    

注意:

由于临时密钥有有效时常限制,所以请注意临时密钥的过期。我们预留了接口供您在过期前更新临时密钥

// 获取新的临时密钥
StsResponse stsResponse = stsClient.getStsResponse(......);
// 更新临时密钥
objectClient.updateTempKeyAndSecret(stsResponse.getAccessKey(), stsResponse.getAccessSecret(), stsResponse.getSecurityToken());
5.6.2 S3相关示例

注意,目前S3相关的云对象存储中,支持STS的只有:华为云、腾讯云、亚马逊、MINIO云;所以如果要使用对象存储的STS功能,请在指定客户端类别时指定以上类型。

华为云:

yaml配置

object-storage:
  end-point: http://obs.your-region.myhuaweicloud.com
sts:
  protocol: S3_HW
  # sts-endpoint: # 华为云云有默认的stsEndpoint,也可以自己指定
  accessKeyId: xxxxxx
  accessKeySecret: xxxxxx
  ima-domain-name: your-domain-name
  ima-user-name: your-ima-user-name
  ima-password: your-ima-user-password
    

腾讯云:

yaml配置

object-storage:
  end-point: cos.your-region.myqcloud.com
sts:  
  access-key-id: xxxxxx
  access-key-secret: xxxxxx
  protocol: S3_COS
  # 腾讯云STS获取临时授权时需要配置region和一个bucket
  bucket: your-bucket
  region: your-region
    

API调用:参见阿里云

AWS、AWS_V4:

yaml配置

object-storage:
  end-point: https://s3.your-region.amazonaws.com
  region: your-region
sts:  
  access-key-id: xxxxxx
  access-key-secret: xxxxxx
  protocol: S3_AWS/S3_AWS_V4
  region: your-region
  role-arn: arn:aws:iam::your:role/name
  external-id: Required # 可选
    

1

API调用:参见阿里云

MINIO:

yaml配置

object-storage:
  end-point: http://your-minio-host:port
sts:
  stsEndpoint: your-sts-endpoint
  access-key-id: xxxxxx # 字用户id
  access-key-secret: xxxxxx # 字用户secret
  protocol: S3_MINIO
 
    

API调用:参见阿里云

5.6.3 注意事项

1.上述示例中指定的各个action,resource请以各个云平台官网为准,如果您需要指定您的action、resource,请参考各个平台对应的官方文档介绍。

2.各个平台对应的指定生成临时秘钥的最短和最长有效时长有差异,请以各个平台官方文档为准,上述示例仅为参考。

3.由于各个平台需要的配置各有差异,所以当您切换平台时,请注意在yaml配置文件中修改相应的配置进行使用。

阿里云:需要配置角色的ARN -> roleArn

华为云:需要配置IAM用户所属账号信息、IAM用户名、IAM用户的登录密码 -> imaDomainName,imaUserName,imaPassword

腾讯云:腾讯云对象存储 获取临时密钥时需要且只能指定一个bucket,且需要指定region -> bucket,region

亚马逊:AWS对象存储需要指定配置角色的ARN和ExternalId(创建用户/角色时指定的)-> roleArn,externalId

MINIO云:需要配置stsEndpoint

4.由于各平台返回的临时秘钥中有效时间格式不同,所以本SDK统一使用阿里云的时间格式:2020-12-02T03:15:56Z,返回GMT时间。

5.6.4 常见错误

1.腾讯云 InvalidParameter.ResouceError

使用腾讯云出现如下错误

{"Response":{"Error":{"Code":"InvalidParameter.ResouceError","Message":"[QC_STS] resource error"},"RequestId":"xxxxxxxx"}}

    

解决方案:

由于腾讯云内部实现中使用了org.json包,所以确保您的应用中存在该包,且没有与其余包(例如:android-json)混淆,出现错误调用。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <artifactId>android-json</artifactId>
            <groupId>com.vaadin.external.google</groupId>
        </exclusion>
    </exclusions>
</dependency>
 

5.7 存储空间操作

5.7.1 创建存储空间

// 创建存储空间 
client.createBucket(bucketName)
client.createBucket(bucketName, aclTypeOption)

5.7.2 判断存储空间是否存在

// 判断存储空间是否存在
client.doesBucketExists(bucketName)

5.7.3 管理存储空间

// 管理存储空间
client.setBucketAcl(bucketName, aclTypeOption)

5.7.4 管理对象权限

// 管理对象权限
client.setObjectAcl(bucketName, objectKey, aclTypeOption)

5.7.5 管理存储空间的跨域规则

// 管理存储空间的跨域规则
client.setBucketCORS(bucketName, allowedMethod, allowedOrigin)

5.7.6 设置生命周期

// 设置声明周期
client.setBucketLifecycle(bucketName, ruleId, prefix, days);

5.7.8 列举存储空间

// 列举存储空间
client.listBuckets()

5.7.7 删除存储空间

// 删除存储空间
client.deleteBucket(bucketName)

5.8 文件基本信息获取

5.8.1 获取文件元信息

// 获取文件元信息
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
client.getObjectMetaData(objectBasicInfo);

5.8.2 获取对象基本信息

//获取对象的基本信息
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
client.getBasicInfo(objectBasicInfo);

5.8.3 获取公共文件的url

// 获取公共文件的url
  ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
  boolean useExternalPoint = true/false;
  client.getPublicObjectUrl(objectBasicInfo, useExternalPoint);

5.8.4 判断对象是否存在

// 判断对象是否存在
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
client.hasObject(objectBasicInfo);

5.8.5 按条件列出所有对象

  // 按条件列出所有对象
  ObjectInfoListing infoListing = null;
	do {
    	infoListing = client.listByPage(objectBasicInfo.getBucketName(), folder, false, (infoListing == null) ? 	(null) : (infoListing.getNextMaker()), 5);
    logger.info(infoListing.getObjectInfos().toString());
  	} while (infoListing.getNextMaker() != null);

5.8.6 获取文件夹内所有对象

// 列出文件夹下所有对象
boolean recursive; //true 代表列出所有的文件,false仅列举当前文件夹的文件
client.listObject(bucketName, objectFolder, recursive)

5.8.7 列出路径下所有文件夹

// 列出路径下所有文件夹
client.listFolders(bucketName, path);

5.8.8 删除文件

// 删除对象
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
client.delete(objectBasicInfo);