上传云对象存储代码实践-阿里云OSS

系列文章目录

第一章 上传云对象存储代码实践-华为云OBS
第二章 上传云对象存储代码实践-阿里云OSS



阿里云OSS


一、阿里云OSS专用名词解释

存储空间(Bucket)

存储空间是OSS中用于存储对象的容器,类似于文件系统中的文件夹,但具有全局唯一性。每个存储空间可设置独立的权限策略、生命周期规则和日志记录。

对象(Object)

对象是OSS存储的基本单元,可以是任意类型的数据(如文本、图片、视频等)。每个对象由键(Key)、数据(Data)和元信息(Metadata)组成,可通过唯一的URL访问。

地域(Region)

地域指OSS数据中心所在的物理位置。用户可选择就近地域创建存储空间,以减少延迟并提高访问速度。不同地域的OSS资源默认隔离。

访问域名(Endpoint)

Endpoint是OSS服务的访问地址,格式为<BucketName>.<Region>.aliyuncs.com。不同地域的Endpoint不同,内网和外网访问需使用对应的域名。

访问密钥(AccessKey)

AccessKey由AccessKey ID和AccessKey Secret组成,用于身份验证和API请求签名。分为主账号AccessKey和子账号RAM用户的AccessKey。

权限控制(ACL)

ACL(Access Control List)用于定义Bucket或Object的访问权限,包括私有(Private)、公共读(Public Read)和公共读写(Public Read/Write)。

生命周期规则(Lifecycle)

生命周期规则可自动管理对象的存储周期,例如自动删除过期文件或转换存储类型(如从标准存储转为低频访问存储)。

跨域资源共享(CORS)

CORS规则允许浏览器跨域访问OSS资源,需在Bucket中配置允许的源(Origin)、方法(Method)和头部(Headers)。

防盗链(Referer)

通过设置Referer白名单或黑名单,限制仅特定来源的请求可访问Bucket资源,防止盗链行为。

数据加密

支持服务器端加密(SSE)和客户端加密。SSE包括OSS完全托管加密(SSE-OSS)和KMS托管加密(SSE-KMS)。

日志记录(Logging)

可开启Bucket访问日志功能,将请求记录保存到指定的Bucket中,便于审计和分析。

图片处理(Image Service)

通过URL参数对存储在OSS中的图片进行裁剪、缩放、水印等实时处理,无需下载原图。

版本控制(Versioning)

启用版本控制后,覆盖或删除Object时会保留旧版本,支持恢复误删或覆盖的文件。

跨区域复制(Cross-Region Replication)

自动将源Bucket中的Object复制到目标Bucket,适用于数据容灾或合规性需求。

传输加速(Transfer Acceleration)

利用全球分布的边缘节点加速文件上传下载,适用于远距离或弱网络环境的数据传输。

冷归档存储(Cold Archive)

适用于极低频访问数据的存储类型,成本最低但 retrieval 时间较长(需解冻)。

碎片(Multipart Upload)

大文件上传时可分片传输,提高稳定性。每个分片需单独上传,最终合并为完整对象。

二、使用步骤和代码实践

OSS对象存储界面创建AK SK

OSS
AK

  • 妥善保存ak sk

创建存储桶,记住桶名,地域节点。

存储桶创建
详情

上传代码JAVA-分片上传

官网流程图
分片上传(Multipart Upload)分为以下三个步骤:

  • 调用InitiateMultipartUpload接口初始化分片上传任务。

  • 调用UploadPart接口上传分片。

  • 要上传的文件切分成Part之后,文件顺序是通过上传过程中指定的partNumber来确定的,实际执行中并没有顺序要求,因此可以实现并发上传。并发数并非越多越快,请结合自身网络状况和设备负载综合考虑。

默认情况下,已经上传但还没有调用CompleteMultipartUpload的Part不会被自动删除,因此如果要终止上传并删除占用的存储空间,需要调用AbortMultipartUpload。

调用CompleteMultipartUpload接口将Part合并为Object。

使用OSS Java SDK完成分片上传的示例代码如下,替换示例中的ak sk、endpoint 、bucketName 、region。

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        String ak = "xxx";
        String sk = "xxx";
        StaticCredentialProvider credentialsProvider = StaticCredentialProvider.create(Credential.builder()
                            .accessKeyId(ak)
                            .accessKeySecret(sk)
                            .build());
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = "exampledir/exampleobject.txt";
        // 待上传本地文件路径。
        String filePath = "D:\\localpath\\examplefile.txt";
        // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
        String region = "cn-hangzhou";

        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // 创建InitiateMultipartUploadRequest对象。
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);

            // 创建ObjectMetadata并设置Content-Type。
            ObjectMetadata metadata = new ObjectMetadata();
            if (metadata.getContentType() == null) {
                metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
            }
            System.out.println("Content-Type: " + metadata.getContentType());

            // 将metadata绑定到上传请求中。
            request.setObjectMetadata(metadata);

            // 初始化分片。
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            // 返回uploadId。
            String uploadId = upresult.getUploadId();

            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
            List<PartETag> partETags = new ArrayList<PartETag>();
            // 每个分片的大小,用于计算文件有多少个分片。单位为字节。
            // 分片最小值为100 KB,最大值为5 GB。最后一个分片的大小允许小于100 KB。
            // 设置分片大小为 1 MB。
            final long partSize = 1 * 1024 * 1024L;   

            // 根据上传的数据大小计算分片数。以本地文件为例,说明如何通过File.length()获取上传数据的大小。
            final File sampleFile = new File(filePath);
            long fileLength = sampleFile.length();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }
            // 遍历分片上传。
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                // 设置上传的分片流。
                // 以本地文件为例说明如何创建FileInputStream,并通过InputStream.skip()方法跳过指定数据。
                InputStream instream = new FileInputStream(sampleFile);
                instream.skip(startPos);
                uploadPartRequest.setInputStream(instream);
                // 设置分片大小。
                uploadPartRequest.setPartSize(curPartSize);
                // 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出此范围,OSS将返回InvalidArgument错误码。
                uploadPartRequest.setPartNumber(i + 1);
                // 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                // 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
                partETags.add(uploadPartResult.getPartETag());

                // 关闭流
                instream.close();
            }

            // 创建CompleteMultipartUploadRequest对象。
            // 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);

            // 完成分片上传。
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            System.out.println("上传成功,ETag:" + completeMultipartUploadResult.getETag());

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught a ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

使用预签名URL下载或预览文件

OSS文件默认为私有权限,只有文件拥有者可访问。但文件拥有者可以生成分享链接(预签名URL),授权他人在有效期内下载或在线预览指定文件。
流程图
工作原理
预签名URL的生成过程依赖密钥加密和参数拼接,过程如下:

  1. 权限校验:您生成预签名URL时需拥有oss:GetObject权限,第三方才能通过该预签名URL成功下载/预览文件;

  2. 本地加密:基于AK/SK对文件路径、过期时间等信息加密计算,得到签名(x-oss-signature);

  3. 附加签名:将签名参数(x-oss-date、x-oss-expires、x-oss-credential 等)作为查询字符串附加到文件URL;

  4. 形成链接:组成完整的预签名URL。

预签名URL格式

https://BucketName.Endpoint/Object?签名参数

完整示例

https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-process=image%2Fresize%2Cp_10&x-oss-date=20241115T095058Z&x-oss-expires=3600&x-oss-sign

以下是java代码的生成文件的下载链接(预签名URL)的代码示例。

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;

import java.net.URL;
import java.util.Date;

public class Demo {
    public static void main(String[] args) throws Throwable {
        // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        String ak = "xxx";
        String sk = "xxx";
        StaticCredentialProvider credentialsProvider = StaticCredentialProvider.create(Credential.builder()
                            .accessKeyId(ak)
                            .accessKeySecret(sk)
                            .build());
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = "exampleobject.txt";
        // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
        String region = "cn-hangzhou";

        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // 设置预签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000L);
            // 生成以GET方法访问的预签名URL。本示例没有额外请求头,其他人可以直接通过浏览器访问相关内容。
            URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
            System.out.println(url);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

参考

阿里云官网OSS上传文档指导

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑞瑞绮绮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值