Rust S3存储插件库s3s的使用,实现高效安全的Amazon S3对象存储操作
Rust S3存储插件库s3s的使用,实现高效安全的Amazon S3对象存储操作
S3 Service Adapter
crate | version | docs |
---|---|---|
s3s | ||
s3s-aws | ||
s3s-fs |
这是一个实验性项目,旨在为构建S3兼容服务提供符合人体工程学的适配器。
s3s
以通用的hyper服务形式实现了Amazon S3 REST API。S3兼容服务可以专注于S3 API本身,而不必关心HTTP层。
s3s-aws
提供了有用的类型并与aws-sdk-s3
集成。
s3s-fs
基于文件系统实现了S3 API,作为一个示例实现。它设计用于集成测试,可以用来模拟S3客户端。它还提供了一个用于调试的二进制文件。
工作原理
上图展示了s3s
的工作原理。
s3s
在调用用户定义的服务之前将HTTP请求转换为操作输入。
s3s
在调用用户定义的服务之后将操作输出或错误转换为HTTP响应。
数据类型、序列化和反序列化是从aws-sdk-rust存储库中的smithy模型生成的。我们应用手动修复来解决smithy服务器代码生成中的一些问题,并使s3s
现在可以使用。
安全性
S3Service
和本项目中的其他适配器没有安全保护。如果它们直接暴露在互联网上,可能会受到攻击。用户需要实现安全增强功能,如HTTP正文长度限制、速率限制和背压。
完整示例代码
use aws_sdk_s3::Client;
use s3s::dto::*;
use s3s::S3ServiceBuilder;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建AWS S3客户端
let config = aws_config::load_from_env().await;
let s3_client = Client::new(&config);
// 创建S3服务适配器
let service = {
let s3 = Arc::new(s3_client);
S3ServiceBuilder::new()
.with_get_object(move |input| {
let s3 = Arc::clone(&s3);
async move {
// 调用AWS SDK获取对象
let output = s3.get_object().bucket(input.bucket).key(input.key).send().await?;
// 转换为s3s响应
Ok(GetObjectOutput {
body: Some(output.body.collect().await?.into_bytes().into()),
..Default::default()
})
}
})
// 可以添加其他操作处理程序
.build()
};
// 将服务绑定到HTTP服务器
let app = hyper::Server::bind(&"0.0.0.0:8000".parse().unwrap())
.serve(s3s::HyperService::new(service));
println!("Server running at http://0.0.0.0:8000");
app.await?;
Ok(())
}
这个示例展示了如何:
- 创建一个AWS S3客户端
- 构建一个S3服务适配器,处理GetObject操作
- 将服务绑定到HTTP服务器
您可以根据需要添加其他操作处理程序,如PutObject、ListObjects等。
扩展完整示例代码
下面是一个更完整的示例,包含PutObject和ListObjects操作处理程序:
use aws_sdk_s3::Client;
use s3s::dto::*;
use s3s::S3ServiceBuilder;
use std::sync::Arc;
use bytes::Bytes;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建AWS S3客户端
let config = aws_config::load_from_env().await;
let s3_client = Client::new(&config);
// 创建S3服务适配器
let service = {
let s3 = Arc::new(s3_client);
S3ServiceBuilder::new()
// 处理GetObject操作
.with_get_object(move |input| {
let s3 = Arc::clone(&s3);
async move {
let output = s3.get_object()
.bucket(input.bucket)
.key(input.key)
.send()
.await?;
Ok(GetObjectOutput {
body: Some(output.body.collect().await?.into_bytes().into()),
..Default::default()
})
}
})
// 处理PutObject操作
.with_put_object(move |input| {
let s3 = Arc::clone(&s3);
async move {
let body = input.body.ok_or("Missing body")?;
let bytes = Bytes::from(body.into_inner());
let _output = s3.put_object()
.bucket(input.bucket)
.key(input.key)
.body(bytes.into())
.send()
.await?;
Ok(PutObjectOutput {
..Default::default()
})
}
})
// 处理ListObjects操作
.with_list_objects(move |input| {
let s3 = Arc::clone(&s3);
async move {
let output = s3.list_objects_v2()
.bucket(input.bucket)
.prefix(input.prefix.unwrap_or_default())
.send()
.await?;
Ok(ListObjectsOutput {
contents: output.contents.map(|list| {
list.into_iter().map(|obj| {
Object {
key: Some(obj.key.unwrap_or_default()),
size: Some(obj.size.unwrap_or_default() as i64),
..Default::default()
}
}).collect()
}),
..Default::default()
})
}
})
.build()
};
// 将服务绑定到HTTP服务器
let app = hyper::Server::bind(&"0.0.0.0:8000".parse().unwrap())
.serve(s3s::HyperService::new(service));
println!("Server running at http://0.0.0.0:8000");
app.await?;
Ok(())
}
这个扩展示例增加了:
- PutObject操作处理程序 - 用于上传对象到S3
- ListObjects操作处理程序 - 用于列出存储桶中的对象
每个操作处理程序都遵循类似的模式:
- 从输入参数中提取必要信息
- 调用AWS SDK执行相应操作
- 将结果转换为s3s的响应格式
您可以根据实际需求继续添加其他S3操作处理程序,或者为现有处理程序添加更多功能和错误处理。
Rust S3存储插件库s3s的使用指南
概述
s3s是一个Rust库,用于高效安全地与Amazon S3对象存储服务进行交互。它提供了简洁的API来执行常见的S3操作,如上传、下载、删除对象等。
安装
在Cargo.toml中添加依赖:
[dependencies]
s3s = "0.1" # 请使用最新版本
tokio = { version = "1.0", features = ["full"] }
基本使用方法
1. 创建S3客户端
use s3s::S3Client;
use s3s::auth::Credentials;
#[tokio::main]
async fn main() {
let credentials = Credentials::new(
"YOUR_ACCESS_KEY_ID",
"YOUR_SECRET_ACCESS_KEY",
None, // 可选的token
None, // 可选的过期时间
);
let client = S3Client::new(
"us-east-1", // 区域
credentials,
).await.unwrap();
}
2. 上传文件到S3
use std::fs::File;
use std::io::Read;
async fn upload_file(client: &S3Client, bucket: &str, key: &str, file_path: &str) {
let mut file = File::open(file_path).unwrap();
let mut contents = Vec::new();
file.read_to_end(&mut contents).unwrap();
client.put_object(bucket, key, contents)
.await
.expect("Failed to upload file");
println!("File uploaded successfully to {}/{}", bucket, key);
}
3. 下载文件从S3
use std::fs::File;
use std::io::Write;
async fn download_file(client: &S3Client, bucket: &str, key: &str, output_path: &str) {
let data = client.get_object(bucket, key)
.await
.expect("Failed to download file");
let mut file = File::create(output_path).unwrap();
file.write_all(&data).unwrap();
println!("File downloaded successfully from {}/{}", bucket, key);
}
4. 列出桶中的对象
async fn list_objects(client: &S3Client, bucket: &str) {
let objects = client list_objects(bucket)
.await
.expect("Failed to list objects");
println!("Objects in bucket {}:", bucket);
for obj in objects {
println!("- {}", obj.key);
}
}
高级功能
1. 使用多部分上传(适合大文件)
use s3s::multipart::MultiPartUpload;
async fn multipart_upload(client: &S3Client, bucket: &str, key: &str, file_path: &str) {
let mut upload = MultiPartUpload::new(client, bucket, key)
.await
.expect("Failed to initiate multipart upload");
let mut file = File::open(file_path).unwrap();
let mut buffer = vec![0; 5 * 1024 * 1024]; // 5MB chunks
loop {
let bytes_read = file.read(&mut buffer).unwrap();
if bytes_read == 0 {
break;
}
upload.upload_part(&buffer[..bytes_read])
.await
.expect("Failed to upload part");
}
upload.complete()
.await
.expect("Failed to complete upload");
println!("Multipart upload completed for {}/{}", bucket, key);
}
2. 设置对象ACL(访问控制)
use s3s::acl::ObjectAcl;
async fn set_object_acl(client: &S3Client, bucket: &str, key: &str) {
client.put_object_acl(
bucket,
key,
ObjectAcl::PublicRead // 或其他ACL选项
)
.await
.expect("Failed to set object ACL");
println!("ACL set for {}/{}", bucket, key);
}
安全注意事项
- 永远不要将访问密钥硬编码在代码中,使用环境变量或安全的密钥管理系统
- 为不同的应用使用不同的IAM用户和权限
- 考虑使用临时安全凭证而不是长期凭证
// 从环境变量读取凭证的更好做法
use std::env;
fn get_credentials_from_env() -> Credentials {
let access_key = env::var("AWS_ACCESS_KEY_ID").expect("AWS_ACCESS_KEY_ID not set");
let secret_key = env::var("AWS_SECRET_ACCESS_KEY").expect("AWS_SECRET_ACCESS_KEY not set");
Credentials::new(&access_key, &secret_key, None, None)
}
错误处理
s3s库提供了详细的错误类型,建议妥善处理:
use s3s::error::S3Error;
async fn safe_operation(client: &S3Client) -> Result<(), S3Error> {
match client.list_objects("my-bucket").await {
Ok(objects) => {
for obj in objects {
println!("Found object: {}", obj.key);
}
Ok(())
},
Err(S3Error::NoSuchBucket) => {
eprintln!("Bucket does not exist");
Ok(())
},
Err(e) => {
eprintln!("S3 operation failed: {}", e);
Err(e)
}
}
}
完整示例代码
下面是一个完整的示例,展示了如何使用s3s库进行基本的S3操作:
use s3s::{S3Client, auth::Credentials};
use std::fs::File;
use std::io::{Read, Write};
use tokio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建S3客户端(从环境变量获取凭证)
let credentials = Credentials::new(
&std::env::var("AWS_ACCESS_KEY_ID")?,
&std::env::var("AWS_SECRET_ACCESS_KEY")?,
None,
None,
);
let client = S3Client::new("us-east-1", credentials).await?;
// 2. 上传文件
let bucket = "my-test-bucket";
let file_key = "test.txt";
let file_path = "./test.txt";
upload_file(&client, bucket, file_key, file_path).await?;
// 3. 列出桶中对象
list_objects(&client, bucket).await?;
// 4. 下载文件
let output_path = "./downloaded_test.txt";
download_file(&client, bucket, file_key, output_path).await?;
Ok(())
}
async fn upload_file(
client: &S3Client,
bucket: &str,
key: &str,
file_path: &str
) -> Result<(), Box<dyn std::error::Error>> {
let mut file = File::open(file_path)?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
client.put_object(bucket, key, contents).await?;
println!("File uploaded successfully to {}/{}", bucket, key);
Ok(())
}
async fn download_file(
client: &S3Client,
bucket: &str,
key: &str,
output_path: &str
) -> Result<(), Box<dyn std::error::Error>> {
let data = client.get_object(bucket, key).await?;
let mut file = File::create(output_path)?;
file.write_all(&data)?;
println!("File downloaded successfully from {}/{}", bucket, key);
Ok(())
}
async fn list_objects(
client: &S3Client,
bucket: &str
) -> Result<(), Box<dyn std::error::Error>> {
let objects = client.list_objects(bucket).await?;
println!("Objects in bucket {}:", bucket);
for obj in objects {
println!("- {}", obj.key);
}
Ok(())
}
这个完整示例展示了如何:
- 从环境变量获取AWS凭证创建S3客户端
- 上传文件到指定S3桶
- 列出桶中的所有对象
- 下载之前上传的文件
使用前请确保:
- 已设置AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY环境变量
- 指定的S3桶已存在
- 本地有测试文件(test.txt)可用于上传