← Cloudflare R2 / r2 / examples / aws
boto3
Вы должны создать ключ доступа перед началом работы. Во всех примерах используется access_key_id и access_key_secret переменные, которые представляют Access Key ID и Secret Access Key значения, которые вы создали.
Настройте boto3 ↗ , чтобы использовать конечную точку R2:
import boto3
s3 = boto3.client(
service_name="s3",
endpoint_url="https://<ACCOUNT_ID>.r2.cloudflarestorage.com",
aws_access_key_id="<ACCESS_KEY_ID>",
aws_secret_access_key="<SECRET_ACCESS_KEY>",
region_name="auto",
)Вы можете опустить aws_access_key_id и aws_secret_access_key если вы установите AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY переменные окружения ↗.
Типичные операции с использованием клиента:
# Get object metadata
s3.head_object(Bucket="my-bucket", Key="dog.png")
# Get object
response = s3.get_object(Bucket="my-bucket", Key="dog.png")
# Upload single file
with open("./dog.png", "rb") as f:
s3.upload_fileobj(f, "my-bucket", "dog.png")
# Delete object
s3.delete_object(Bucket="my-bucket", Key="dog.png")Оптимизация производительности загрузки
Для больших объектов (файлы размером в несколько гигабайт, например обучающие данные или видео) upload_fileobj может стать узким местом по пропускной способности. Его внутренний пул потоков ограничивается в Python GIL ↗, и увеличение max_concurrency через TransferConfig даёт всё меньший прирост при использовании более примерно 10 потоков.
Вместо этого используйте низкоуровневый multipart API с ThreadPoolExecutor вместо этого:
import boto3
import math
import os
from concurrent.futures import ThreadPoolExecutor
s3 = boto3.client(
service_name="s3",
endpoint_url="https://<ACCOUNT_ID>.r2.cloudflarestorage.com",
aws_access_key_id="<ACCESS_KEY_ID>",
aws_secret_access_key="<SECRET_ACCESS_KEY>",
region_name="auto",
)
bucket = "my-bucket"
key = "large-file.bin"
file_path = "./large-file.bin"
part_size = 16 * 1024 * 1024 # 16 MiB per part
max_workers = 10
# Step 1: Create the multipart upload
upload_id = None
mpu = s3.create_multipart_upload(Bucket=bucket, Key=key)
upload_id = mpu["UploadId"]
def upload_part(part_number, data):
response = s3.upload_part(
Bucket=bucket,
Key=key,
UploadId=upload_id,
PartNumber=part_number,
Body=data,
)
return {"PartNumber": part_number, "ETag": response["ETag"]}
try:
file_size = os.path.getsize(file_path)
part_count = math.ceil(file_size / part_size)
# Step 2: Upload parts in parallel
with ThreadPoolExecutor(max_workers=max_workers) as pool:
futures = []
with open(file_path, "rb") as f:
for i in range(part_count):
data = f.read(part_size)
futures.append(pool.submit(upload_part, i + 1, data))
parts = [future.result() for future in futures]
# Step 3: Complete the upload
s3.complete_multipart_upload(
Bucket=bucket,
Key=key,
UploadId=upload_id,
MultipartUpload={"Parts": parts},
)
print("Multipart upload complete.")
except Exception:
if upload_id:
try:
s3.abort_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id)
except Exception:
pass
raiseПодробнее о составных загрузках, включая ограничения на размер частей и управление жизненным циклом, см. Загрузка объектов.
Создание presigned URL
Создавайте presigned-ссылки, чтобы предоставлять временный публичный доступ на чтение или запись к бакету.
# Generate presigned URL for reading (GET)
get_url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": "my-bucket", "Key": "dog.png"},
ExpiresIn=3600, # Valid for 1 hour
)
# Generate presigned URL for writing (PUT)
put_url = s3.generate_presigned_url(
"put_object",
Params={
"Bucket": "my-bucket",
"Key": "dog.png",
"ContentType": "image/png",
},
ExpiresIn=3600,
)https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>
https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>Выполните загрузку с помощью presigned PUT URL. При использовании presigned URL с ContentType, клиент должен включить соответствующий Content-Type заголовок:
curl -X PUT "https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=..." \
-H "Content-Type: image/png" \
--data-binary @dog.pngОграничение загрузок с помощью CORS и Content-Type
При создании presigned URL для загрузки злоупотребления и неправильное использование можно ограничить следующими способами:
-
Ограничение Content-Type: укажите допустимый тип содержимого в параметрах подписанного URL. Если клиент отправит другой
Content-Typeзаголовок. -
Настройка CORS: настройте Правила CORS для вашего бакета, чтобы определить, какие источники могут загружать файлы. Настройте CORS через Панель управления Cloudflare ↗ добавив JSON-политику в настройки бакета:
[
{
"AllowedOrigins": ["https://example.com"],
"AllowedMethods": ["PUT"],
"AllowedHeaders": ["Content-Type"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]Затем создайте presigned URL с ограничением Content-Type:
put_url = s3.generate_presigned_url(
"put_object",
Params={
"Bucket": "my-bucket",
"Key": "dog.png",
"ContentType": "image/png",
},
ExpiresIn=3600,
)Используя такой presigned URL, клиент должен:
- Отправьте запрос с разрешённого источника (это обеспечивается CORS)
- Включите
Content-Type: image/pngзаголовок (обеспечивается подписью)