Работа с S3 и облачными хранилищами в Rust: библиотека aws-sdk-s3

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с S3 и облачными хранилищами в Rust: aws-sdk-s3

Облачные объектные хранилища, совместимые с Amazon S3, стали стандартом де-факто для хранения файлов, бэкапов, статики и данных. В экосистеме Rust для работы с S3 используется официальный AWS SDK для Rust — aws-sdk-s3. Этот инструмент позволяет не только подключаться к Amazon S3, но и к любым S3-совместимым хранилищам: MinIO, Yandex Object Storage, DigitalOcean Spaces, Cloudflare R2 и другим.

Установка и настройка

Добавьте в Cargo.toml следующие зависимости:

[dependencies]
aws-sdk-s3 = "1.15"
aws-config = "1.1"
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"

Для аутентификации можно использовать переменные окружения, файл конфигурации AWS (~/.aws/credentials) или передавать ключи программно. Минимальная инициализация клиента выглядит так:

use aws_sdk_s3::Client;
use aws_config::meta::region::RegionProviderChain;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    let region_provider = RegionProviderChain::default_provider()
        .or_else("ru-central1");
    let config = aws_config::from_env()
        .region(region_provider)
        .load()
        .await;
    let client = Client::new(&config);
    // Далее работаем с client
    Ok(())
}

Основные операции с S3

Создание бакета

use aws_sdk_s3::model::BucketLocationConstraint;

let bucket_name = "my-rust-bucket";
let constraint = BucketLocationConstraint::from("ru-central1");
let _ = client
    .create_bucket()
    .bucket(bucket_name)
    .create_bucket_configuration(
        aws_sdk_s3::model::CreateBucketConfiguration::builder()
            .location_constraint(constraint)
            .build()
    )
    .send()
    .await?;

Загрузка файла (PutObject)

use aws_sdk_s3::primitives::ByteStream;
use std::path::Path;

let file_path = "local_file.txt";
let body = ByteStream::from_path(Path::new(file_path)).await?;

client
    .put_object()
    .bucket(bucket_name)
    .key("uploads/remote_file.txt")
    .body(body)
    .send()
    .await?;
println!("Файл загружен");

Скачивание файла (GetObject)

use tokio::io::AsyncWriteExt;

let resp = client
    .get_object()
    .bucket(bucket_name)
    .key("uploads/remote_file.txt")
    .send()
    .await?;

let mut file = tokio::fs::File::create("downloaded.txt").await?;
let mut stream = resp.body;
while let Some(chunk) = stream.try_next().await? {
    file.write_all(&chunk).await?;
}
println!("Файл скачан");

Список объектов в бакете

let objects = client
    .list_objects_v2()
    .bucket(bucket_name)
    .prefix("uploads/")
    .send()
    .await?;

for obj in objects.contents().unwrap_or_default() {
    println!("- {}", obj.key().unwrap_or("unknown"));
}

Подключение к MinIO и другим S3-совместимым хранилищам

Для работы с MinIO (или любым другим не-AWS хранилищем) необходимо переопределить endpoint и отключить проверку сигнатуры региона (если требуется). Вот полный пример:

use aws_sdk_s3::{Client, Config, Credentials, Region};
use aws_smithy_client::erase::DynConnector;
use aws_smithy_client::hyper_ext;
use http::Uri;

let creds = Credentials::new(
    "minioadmin",
    "minioadmin",
    None,
    None,
    "minio",
);

let endpoint = Uri::from_static("http://localhost:9000");
let region = Region::new("us-east-1");

let config = Config::builder()
    .credentials_provider(creds)
    .region(region)
    .endpoint_resolver(endpoint)
    .force_path_style(true)  // Важно для MinIO
    .build();

let client = Client::from_conf(config);
// Все операции с client теперь идут через MinIO

Обратите внимание на force_path_style(true) — многие S3-совместимые хранилища (особенно старые версии MinIO) требуют path-style доступа (bucket в пути URL), а не виртуального хостинга.

Работа с большими файлами (Multipart Upload)

Для файлов размером более 100 МБ рекомендуется использовать multipart upload. В aws-sdk-s3 это реализовано через отдельные шаги:

use aws_sdk_s3::model::{CompletedPart, CompletedMultipartUpload};

// 1                    

Рекомендаций