本文用于记录与分享工作中遇到的s3的基础使用方法
工具介绍
本文采用s3Browser对s3进行可视化管理
基本元素
- 端点Endpoint
- 桶Bucket
- 账号AccessKey
- 密码SecreteKey
说明
本文基于JavaSDK进行演示代码,下文的代码都只包含核心部分,异常捕捉、流关闭、S3客户端、端点信息等细节可能会被省略
Maven依赖
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.11.891</version>
</dependency>
s3Browser下载地址
https://s3browser.com/download.aspx
存储桶管理
S3上的数据都是存储在桶内的,可以理解为自己账号下的文件夹。桶之间是隔离的。
命名规范
推荐桶名称如下:
docexamplebucket1
log-delivery-march-2020
my-hosted-content
无效桶名称:
doc_example_bucket(包含下划线)
DocExampleBucket(包含大写字母)
doc-example-bucket-(以连字符结尾)
桶的访问方式(端点访问)
这里简单介绍一下几种常用的端点命名访问方式
虚拟主机(推荐使用)
url = https://桶名.[区域码].端点地址/文件key
可选参数:区域码
路径类型
url = https://[区域码].端点地址/桶名/文件key
自定义域名
- 将自己的域名,cname到厂商的S3 Endpoint上
- 在配置页面,将域名映射到某个桶
url = https://自定义域名/桶名/文件key
创建桶
// 声明区域
Regions clientRegion = Regions.DEFAULT_REGION;
String bucketName = "桶名在这里定义";
// s3客户端
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new ProfileCredentialsProvider())
.withRegion(clientRegion)
.build();
if (!s3Client.doesBucketExistV2(bucketName)) {
s3Client.createBucket(new CreateBucketRequest(bucketName));
// 验证桶创建成功
String bucketLocation = s3Client.getBucketLocation(new GetBucketLocationRequest(bucketName));
System.out.println("Bucket location: " + bucketLocation);
删除桶
// 删除所有对象
ObjectListing objectListing = s3Client.listObjects(bucketName);
while (true) {
Iterator<S3ObjectSummary> objIter = objectListing.getObjectSummaries().iterator();
while (objIter.hasNext()) {
s3Client.deleteObject(bucketName, objIter.next().getKey());
}
if (objectListing.isTruncated()) {
objectListing = s3Client.listNextBatchOfObjects(objectListing);
} else {
break;
}
}
// 删除所有带版本的对象
VersionListing versionList = s3Client.listVersions(new ListVersionsRequest().withBucketName(bucketName));
while (true) {
Iterator<S3VersionSummary> versionIter = versionList.getVersionSummaries().iterator();
while (versionIter.hasNext()) {
S3VersionSummary vs = versionIter.next();
s3Client.deleteVersion(bucketName, vs.getKey(), vs.getVersionId());
}
if (versionList.isTruncated()) {
versionList = s3Client.listNextBatchOfVersions(versionList);
} else {
break;
}
}
// 删除桶
s3Client.deleteBucket(bucketName);
}
对象管理
上传对象
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.build();
// 上传一个对象 这里传入一个String
s3Client.putObject(bucketName, stringObjKeyName, "Uploaded String Object");
// 指定ContentType 从文件上传对象
PutObjectRequest request = new PutObjectRequest(bucketName, fileObjKeyName, new File(fileName));
// 对象元数据设置
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("plain/text");
metadata.addUserMetadata("title", "someTitle");
request.setMetadata(metadata);
s3Client.putObject(request);
下载对象
S3Object fullObject = null, objectPortion = null, headerOverrideObject = null;
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ProfileCredentialsProvider())
.build();
// 获取对象
fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
// 获取对象指定字节范围
GetObjectRequest rangeObjectRequest = new GetObjectRequest(bucketName, key)
.withRange(0, 9);
objectPortion = s3Client.getObject(rangeObjectRequest);
// 指定ResponseHeader
ResponseHeaderOverrides headerOverrides =
new ResponseHeaderOverrides()
.withCacheControl("No-cache")
.withContentDisposition("attachment; filename=example.txt");
GetObjectRequest getObjectRequestHeaderOverride =
new GetObjectRequest(bucketName, key)
.withResponseHeaders(headerOverrides);
headerOverrideObject = s3Client.getObject(getObjectRequestHeaderOverride);
复制对象
// 从bucketName/sourceKey复制到bucketName2/destinationKey
CopyObjectRequest copyObjRequest = new CopyObjectRequest(bucketName, sourceKey, bucketName2, destinationKey);
s3Client.copyObject(copyObjRequest);
删除对象
// 删除单个对象
s3Client.deleteObject(new DeleteObjectRequest(bucketName, keyName));
// 删除多个对象
// 文件名
ArrayList<KeyVersion> keys = new ArrayList<KeyVersion>();
for (int i = 0; i < 3; i++) {
String keyName = "keyname " + i;
keys.add(new KeyVersion(keyName));
}
// 删除多个对象
DeleteObjectsRequest multiObjectDeleteRequest = new DeleteObjectsRequest(bucketName)
.withKeys(keys)
.withQuiet(false);
// 验证删除成功
DeleteObjectsResult delObjRes = s3Client.deleteObjects(multiObjectDeleteRequest);
int successfulDeletes = delObjRes.getDeletedObjects().size();
列出对象
可以列出桶里所有文件的路径
ListObjectsRequest listObjects = new ListObjectsRequest().withBucketName("ait-doc");
// 查看所有对象
ObjectListing res = amazonS3.listObjects(listObjects);
List<S3ObjectSummary> objectSummaries = res.getObjectSummaries();
for (S3ObjectSummary myValue : objectSummaries) {
System.out.print("\n 文件路径:" + myValue.getKey());
}
分段上传
这里通常有两种API提供给我们使用,第一种是高级API,使用的是TransferManager实现调用,第二种是更底层的低级API,通常我用低级API,更方便定制化开发。
配置生命周期策略
此项用于指定分段上传任务在指定天数内完成上传,否则将会被清除相关联的分段
<LifecycleConfiguration>
<Rule>
<ID>sample-rule</ID>
<Prefix></Prefix>
<Status>Enabled</Status>
<AbortIncompleteMultipartUpload>
<DaysAfterInitiation>7</DaysAfterInitiation>
</AbortIncompleteMultipartUpload>
</Rule>
</LifecycleConfiguration>
查看正在进行的分段上传的列表
ListMultipartUploadsRequest allMultpartUploadsRequest =
new ListMultipartUploadsRequest(existingBucketName);
MultipartUploadListing multipartUploadListing =
s3Client.listMultipartUploads(allMultpartUploadsRequest);
分段上传
分段上传通常用于大文件,前后端配合实现快速上传。
通常分段上传分为三个步骤:
- 开启分段上传任务
- 上传分段数据
- 结束或中断分段上传任务
任务结束后,会汇聚所有的分段,合并为一个完整的文件,所有的操作都是由S3实现的。
// 分段标签元数据
List<PartETag> partETags = new ArrayList<PartETag>();
// 发起开始分段上传请求
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, keyName);
InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);
// 上传分段
long filePosition = 0;
for (int i = 1; filePosition < contentLength; i++) {
// 最后一个分段可能小于5MB,
partSize = Math.min(partSize, (contentLength - filePosition));
// 分段上传请求
UploadPartRequest uploadRequest = new UploadPartRequest()
.withBucketName(bucketName)
.withKey(keyName)
.withUploadId(initResponse.getUploadId())
.withPartNumber(i)
.withFileOffset(filePosition)
.withFile(file)
.withPartSize(partSize);
// 分段上传响应
UploadPartResult uploadResult = s3Client.uploadPart(uploadRequest);
partETags.add(uploadResult.getPartETag());
filePosition += partSize;
}
// 关闭分段上传任务
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucketName, keyName,
initResponse.getUploadId(), partETags);
s3Client.completeMultipartUpload(compRequest);
中断分段上传
如果不需要结束任务,那么可以中断上传,然后会清理掉所有的分段。
// 低级API
s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(
existingBucketName, keyName, initResponse.getUploadId()));
// 高级API
TransferManager tm = new TransferManager(new ProfileCredentialsProvider());
// 指定清理一周前启动的 并且还在进行上传的分段
int sevenDays = 1000 * 60 * 60 * 24 * 7;
Date oneWeekAgo = new Date(System.currentTimeMillis() - sevenDays);
tm.abortMultipartUploads(existingBucketName, oneWeekAgo);
跟踪正在上传的分段
TransferManager tm = new TransferManager(new ProfileCredentialsProvider());
PutObjectRequest request = new PutObjectRequest(
existingBucketName, keyName, new File(filePath));
// 设置监听事件
request.setGeneralProgressListener(new ProgressListener() {
@Override
public void progressChanged(ProgressEvent progressEvent) {
System.out.println("Transferred bytes: " +
progressEvent.getBytesTransferred());
}
});
// 执行上传
Upload upload = tm.upload(request);
// 等待上传完毕
upload.waitForCompletion();
低级API(TransferManager)
TransferManager tm = TransferManagerBuilder.standard()
.withS3Client(s3Client)
.build();
// 指定文件路径上传
Upload upload = tm.upload(bucketName, keyName, new File(filePath));
// 异步 等待任务完成
upload.waitForCompletion();
预签名URL
签名URL上传
// 生成请求
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest("ait-doc", "1.png")
// 查询请求用GET 上传请求用PUT
.withMethod(HttpMethod.GET)
.withExpiration(new Date());
// 创建签名URL
URL url = amazonS3.generatePresignedUrl(request);
安全管理
CORS
可以进行跨域配置
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
</CORSRule>
</CORSConfiguration>
ACL管理访问
管理桶和对象的访问权限,附加在桶和对象上,进行权限控制。S3提供了一系列预定义的ACL叫标准ACL,下表是常用3个的标准ACL。可以使用 x-amz-acl 请求头在请求中指定标准的 ACL。
ACL | 适用 | 权限描述 |
---|---|---|
private | 桶和对象 | 所有者将获得 FULL_CONTROL。其他人没有访问权限 (默认) |
public-read | 桶和对象 | |
public-read-write | 桶和对象 | 所有者将获得 FULL_CONTROL。AllUsers 组将获得 READ 访问权限 |
参考:
[1] AWS GIthub仓库
[2] AWS官方文档