Bucket 管理
📦 Bucket 概述
Bucket(存储桶)是 S3 中用于存储对象的容器,类似于文件系统中的顶级目录。所有对象都必须存储在 Bucket 中。
🔑 Bucket 特性
命名规则
✅ 有效的 Bucket 名称:
- my-app-images
- company-backups-2024
- user.data.bucket
❌ 无效的 Bucket 名称:
- MyAppImages (不能有大写)
- my_app_images (不推荐使用下划线)
- 192.168.1.1 (不能是 IP 地址格式)
- -my-bucket (不能以连字符开头)
- my-bucket- (不能以连字符结尾)
规则:
1. 长度:3-63 个字符
2. 字符:小写字母、数字、连字符(-)、点号(.)
3. 格式:必须以字母或数字开头和结尾
4. 唯一性:全球唯一(跨所有 AWS 账户)
5. 不可更改:创建后无法重命名Bucket 属性
javascript
Bucket 包含以下属性:
├── Name: 全局唯一名称
├── Region: 所属区域
├── Versioning: 版本控制
├── Encryption: 加密设置
├── Access Control: 访问控制
├── Lifecycle Rules: 生命周期规则
├── Tags: 标签
└── Logging: 日志记录🚀 创建 Bucket
Node.js SDK
javascript
const AWS = require('aws-sdk');
const s3 = new AWS.S3({ region: 'us-east-1' });
// 基本创建
const createBucket = async (bucketName) => {
try {
await s3.createBucket({
Bucket: bucketName
}).promise();
console.log(`Bucket ${bucketName} created successfully`);
} catch (err) {
if (err.code === 'BucketAlreadyExists') {
console.error('Bucket name already taken');
} else if (err.code === 'BucketAlreadyOwnedByYou') {
console.log('You already own this bucket');
} else {
console.error(err);
}
}
};
// 在特定区域创建
const createBucketInRegion = async (bucketName, region) => {
const s3 = new AWS.S3({ region });
const params = {
Bucket: bucketName,
CreateBucketConfiguration: {
LocationConstraint: region // 注意:us-east-1 不需要此参数
}
};
try {
await s3.createBucket(params).promise();
console.log(`Bucket ${bucketName} created in ${region}`);
} catch (err) {
console.error(err);
}
};
// 创建并设置 ACL
const createBucketWithACL = async (bucketName) => {
try {
await s3.createBucket({
Bucket: bucketName,
ACL: 'private' // private | public-read | public-read-write
}).promise();
console.log('Bucket created with ACL');
} catch (err) {
console.error(err);
}
};AWS CLI
bash
# 创建 Bucket
aws s3 mb s3://my-bucket-name
# 在特定区域创建
aws s3 mb s3://my-bucket-name --region us-west-2
# 使用 s3api 创建(更多选项)
aws s3api create-bucket \
--bucket my-bucket-name \
--region us-west-2 \
--create-bucket-configuration LocationConstraint=us-west-2📋 列出 Bucket
列出所有 Bucket
javascript
const listBuckets = async () => {
try {
const result = await s3.listBuckets().promise();
console.log('Your buckets:');
result.Buckets.forEach(bucket => {
console.log(`- ${bucket.Name} (Created: ${bucket.CreationDate})`);
});
return result.Buckets;
} catch (err) {
console.error(err);
}
};AWS CLI
bash
# 列出所有 Bucket
aws s3 ls
# 输出示例:
# 2024-01-01 12:00:00 my-app-images
# 2024-01-02 13:30:00 company-backups🔍 获取 Bucket 信息
获取 Bucket 位置
javascript
const getBucketLocation = async (bucketName) => {
try {
const result = await s3.getBucketLocation({
Bucket: bucketName
}).promise();
console.log(`Bucket location: ${result.LocationConstraint || 'us-east-1'}`);
return result.LocationConstraint;
} catch (err) {
console.error(err);
}
};检查 Bucket 是否存在
javascript
const bucketExists = async (bucketName) => {
try {
await s3.headBucket({ Bucket: bucketName }).promise();
return true;
} catch (err) {
if (err.code === 'NotFound') {
return false;
}
throw err;
}
};🗑️ 删除 Bucket
删除空 Bucket
javascript
const deleteBucket = async (bucketName) => {
try {
// 先检查 Bucket 是否为空
const objects = await s3.listObjectsV2({
Bucket: bucketName,
MaxKeys: 1
}).promise();
if (objects.Contents && objects.Contents.length > 0) {
throw new Error('Bucket is not empty. Delete all objects first.');
}
await s3.deleteBucket({ Bucket: bucketName }).promise();
console.log(`Bucket ${bucketName} deleted`);
} catch (err) {
console.error(err);
}
};删除非空 Bucket
javascript
const emptyAndDeleteBucket = async (bucketName) => {
try {
// 1. 列出所有对象
let isTruncated = true;
let continuationToken = undefined;
while (isTruncated) {
const listParams = {
Bucket: bucketName,
ContinuationToken: continuationToken
};
const listResult = await s3.listObjectsV2(listParams).promise();
if (listResult.Contents && listResult.Contents.length > 0) {
// 2. 批量删除对象
const deleteParams = {
Bucket: bucketName,
Delete: {
Objects: listResult.Contents.map(obj => ({ Key: obj.Key }))
}
};
await s3.deleteObjects(deleteParams).promise();
console.log(`Deleted ${listResult.Contents.length} objects`);
}
isTruncated = listResult.IsTruncated;
continuationToken = listResult.NextContinuationToken;
}
// 3. 删除版本(如果启用了版本控制)
await deleteAllVersions(bucketName);
// 4. 删除 Bucket
await s3.deleteBucket({ Bucket: bucketName }).promise();
console.log(`Bucket ${bucketName} deleted successfully`);
} catch (err) {
console.error(err);
}
};
// 删除所有版本
const deleteAllVersions = async (bucketName) => {
let keyMarker = undefined;
let versionMarker = undefined;
while (true) {
const params = {
Bucket: bucketName,
KeyMarker: keyMarker,
VersionIdMarker: versionMarker
};
const result = await s3.listObjectVersions(params).promise();
// 删除所有版本和删除标记
const objectsToDelete = [
...(result.Versions || []).map(v => ({ Key: v.Key, VersionId: v.VersionId })),
...(result.DeleteMarkers || []).map(d => ({ Key: d.Key, VersionId: d.VersionId }))
];
if (objectsToDelete.length > 0) {
await s3.deleteObjects({
Bucket: bucketName,
Delete: { Objects: objectsToDelete }
}).promise();
}
if (!result.IsTruncated) break;
keyMarker = result.NextKeyMarker;
versionMarker = result.NextVersionIdMarker;
}
};AWS CLI
bash
# 删除空 Bucket
aws s3 rb s3://my-bucket-name
# 删除非空 Bucket(先删除所有对象)
aws s3 rb s3://my-bucket-name --force🏷️ Bucket 标签
标签用于分类和成本分配。
javascript
// 设置标签
const setBucketTags = async (bucketName) => {
const params = {
Bucket: bucketName,
Tagging: {
TagSet: [
{ Key: 'Environment', Value: 'Production' },
{ Key: 'Project', Value: 'MyApp' },
{ Key: 'CostCenter', Value: 'Engineering' }
]
}
};
try {
await s3.putBucketTagging(params).promise();
console.log('Tags set successfully');
} catch (err) {
console.error(err);
}
};
// 获取标签
const getBucketTags = async (bucketName) => {
try {
const result = await s3.getBucketTagging({
Bucket: bucketName
}).promise();
console.log('Bucket tags:');
result.TagSet.forEach(tag => {
console.log(`${tag.Key}: ${tag.Value}`);
});
return result.TagSet;
} catch (err) {
if (err.code === 'NoSuchTagSet') {
console.log('No tags found');
return [];
}
console.error(err);
}
};
// 删除标签
const deleteBucketTags = async (bucketName) => {
try {
await s3.deleteBucketTagging({
Bucket: bucketName
}).promise();
console.log('Tags deleted');
} catch (err) {
console.error(err);
}
};🔐 Bucket 加密
服务端加密(SSE)
javascript
// 启用默认加密(SSE-S3)
const enableEncryption = async (bucketName) => {
const params = {
Bucket: bucketName,
ServerSideEncryptionConfiguration: {
Rules: [
{
ApplyServerSideEncryptionByDefault: {
SSEAlgorithm: 'AES256' // S3 管理的密钥
},
BucketKeyEnabled: true // 降低加密成本
}
]
}
};
try {
await s3.putBucketEncryption(params).promise();
console.log('Encryption enabled');
} catch (err) {
console.error(err);
}
};
// 使用 KMS 加密
const enableKMSEncryption = async (bucketName, kmsKeyId) => {
const params = {
Bucket: bucketName,
ServerSideEncryptionConfiguration: {
Rules: [
{
ApplyServerSideEncryptionByDefault: {
SSEAlgorithm: 'aws:kms',
KMSMasterKeyID: kmsKeyId
},
BucketKeyEnabled: true
}
]
}
};
await s3.putBucketEncryption(params).promise();
};
// 获取加密配置
const getEncryption = async (bucketName) => {
try {
const result = await s3.getBucketEncryption({
Bucket: bucketName
}).promise();
console.log('Encryption:', result.ServerSideEncryptionConfiguration);
return result;
} catch (err) {
if (err.code === 'ServerSideEncryptionConfigurationNotFoundError') {
console.log('No encryption configured');
} else {
console.error(err);
}
}
};🌐 跨域资源共享(CORS)
javascript
const setCORS = async (bucketName) => {
const params = {
Bucket: bucketName,
CORSConfiguration: {
CORSRules: [
{
AllowedHeaders: ['*'],
AllowedMethods: ['GET', 'PUT', 'POST', 'DELETE'],
AllowedOrigins: ['https://example.com', 'https://*.example.com'],
ExposeHeaders: ['ETag', 'x-amz-meta-custom-header'],
MaxAgeSeconds: 3600
}
]
}
};
try {
await s3.putBucketCors(params).promise();
console.log('CORS configured');
} catch (err) {
console.error(err);
}
};
// 获取 CORS 配置
const getCORS = async (bucketName) => {
try {
const result = await s3.getBucketCors({
Bucket: bucketName
}).promise();
console.log('CORS rules:', result.CORSRules);
return result;
} catch (err) {
console.error(err);
}
};📊 Bucket 指标和监控
javascript
// 启用请求指标
const enableMetrics = async (bucketName) => {
const params = {
Bucket: bucketName,
Id: 'EntireBucket',
MetricsConfiguration: {
Id: 'EntireBucket'
}
};
await s3.putBucketMetricsConfiguration(params).promise();
console.log('Metrics enabled');
};
// 查看 CloudWatch 指标
// 可以在 AWS 控制台的 CloudWatch 中查看:
// - NumberOfObjects: 对象数量
// - BucketSizeBytes: 存储大小
// - AllRequests: 总请求数
// - GetRequests: GET 请求数
// - PutRequests: PUT 请求数💡 最佳实践
1. 命名约定
javascript
// ✅ 好的命名
'company-app-images-prod'
'project-logs-2024'
'user-uploads-staging'
// ❌ 避免
'MyBucket' // 大写
'bucket_name' // 下划线
'test' // 太通用2. 区域选择
javascript
// 选择最近的区域以降低延迟
const regionByLocation = {
'US-East': 'us-east-1',
'US-West': 'us-west-2',
'EU': 'eu-west-1',
'Asia': 'ap-northeast-1'
};
// 考虑数据主权和合规性
// 例如:GDPR 要求数据存储在欧盟3. 成本优化
javascript
// 使用生命周期策略自动转换存储类别
// 定期清理不需要的数据
// 启用 Bucket 分析以了解访问模式4. 安全性
javascript
// 始终加密敏感数据
// 使用 Bucket Policy 和 IAM 策略控制访问
// 启用版本控制以防止意外删除
// 定期审查权限📖 相关资源
下一步:学习 对象操作 📝