Loading...
Loading...
Compare original and translation side by side
npm install -g wrangler
wrangler loginnpm install -g wrangler
wrangler loginprocess.env<project-root>/.env.claude/.env.claude/skills/.env.claude/skills/cloudflare-r2/.envundefinedprocess.env<project-root>/.env.claude/.env.claude/skills/.env.claude/skills/cloudflare-r2/.envundefined
**Where to Get Credentials:**
- R2 Access Keys: Cloudflare Dashboard → R2 → Manage R2 API Tokens → Create API Token
- Generates both Access Key ID and Secret Access Key (S3-compatible)
- Account ID: Cloudflare Dashboard → Overview → Account ID (right sidebar)
- API Token (for Wrangler): Cloudflare Dashboard → My Profile → API Tokens
**Example .env File:**
```bash
**凭证获取路径:**
- R2访问密钥:Cloudflare控制台 → R2 → 管理R2 API令牌 → 创建API令牌
- 会同时生成Access Key ID和Secret Access Key(兼容S3)
- 账户ID:Cloudflare控制台 → 概览 → 账户ID(右侧边栏)
- API令牌(用于Wrangler):Cloudflare控制台 → 我的资料 → API令牌
**示例.env文件:**
```bashundefinedundefinedwrangler r2 bucket create my-bucketwrangler r2 bucket create my-bucket --location=wnamwnamenamweureeurapacwrangler r2 bucket create my-bucketwrangler r2 bucket create my-bucket --location=wnamwnamenamweureeurapacwrangler r2 object put my-bucket/file.txt --file=./local-file.txtawait env.MY_BUCKET.put('file.txt', fileContents, {
httpMetadata: {
contentType: 'text/plain',
},
});wrangler r2 object put my-bucket/file.txt --file=./local-file.txtawait env.MY_BUCKET.put('file.txt', fileContents, {
httpMetadata: {
contentType: 'text/plain',
},
});wrangler r2 object get my-bucket/file.txt --file=./downloaded.txtconst object = await env.MY_BUCKET.get('file.txt');
const contents = await object.text();wrangler r2 object get my-bucket/file.txt --file=./downloaded.txtconst object = await env.MY_BUCKET.get('file.txt');
const contents = await object.text();[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
preview_bucket_name = "my-bucket-preview"[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
preview_bucket_name = "my-bucket-preview"await env.MY_BUCKET.put('user-uploads/photo.jpg', imageData, {
httpMetadata: {
contentType: 'image/jpeg',
cacheControl: 'public, max-age=31536000',
},
customMetadata: {
uploadedBy: userId,
uploadDate: new Date().toISOString(),
},
});const object = await env.MY_BUCKET.get('large-file.mp4');
if (object === null) {
return new Response('Not found', { status: 404 });
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata.contentType,
'ETag': object.etag,
},
});const listed = await env.MY_BUCKET.list({
prefix: 'user-uploads/',
limit: 100,
});
for (const object of listed.objects) {
console.log(object.key, object.size);
}await env.MY_BUCKET.delete('old-file.txt');const object = await env.MY_BUCKET.head('file.txt');
if (object) {
console.log('Exists:', object.size, 'bytes');
}await env.MY_BUCKET.put('user-uploads/photo.jpg', imageData, {
httpMetadata: {
contentType: 'image/jpeg',
cacheControl: 'public, max-age=31536000',
},
customMetadata: {
uploadedBy: userId,
uploadDate: new Date().toISOString(),
},
});const object = await env.MY_BUCKET.get('large-file.mp4');
if (object === null) {
return new Response('Not found', { status: 404 });
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata.contentType,
'ETag': object.etag,
},
});const listed = await env.MY_BUCKET.list({
prefix: 'user-uploads/',
limit: 100,
});
for (const object of listed.objects) {
console.log(object.key, object.size);
}await env.MY_BUCKET.delete('old-file.txt');const object = await env.MY_BUCKET.head('file.txt');
if (object) {
console.log('Exists:', object.size, 'bytes');
}aws configureaws configure
**Operations:**
```bash
**操作命令:**
```bashundefinedundefinedimport { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({
region: "auto",
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
});
await s3.send(new PutObjectCommand({
Bucket: "my-bucket",
Key: "file.txt",
Body: fileContents,
}));import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({
region: "auto",
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
});
await s3.send(new PutObjectCommand({
Bucket: "my-bucket",
Key: "file.txt",
Body: fileContents,
}));import boto3
s3 = boto3.client(
service_name="s3",
endpoint_url=f'https://{account_id}.r2.cloudflarestorage.com',
aws_access_key_id=access_key_id,
aws_secret_access_key=secret_access_key,
region_name="auto",
)import boto3
s3 = boto3.client(
service_name="s3",
endpoint_url=f'https://{account_id}.r2.cloudflarestorage.com',
aws_access_key_id=access_key_id,
aws_secret_access_key=secret_access_key,
region_name="auto",
)undefinedundefinedrclone configrclone config
**Upload with multipart optimization:**
```bash
**分段上传优化:**
```bashundefinedundefinedwrangler r2 bucket create my-public-bucketwrangler r2 bucket create my-public-bucketundefinedundefinedhttps://pub-<hash>.r2.dev/file.txthttps://pub-<hash>.r2.dev/file.txtwrangler r2 bucket cors put my-bucket --rules '[
{
"AllowedOrigins": ["https://example.com"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]'wrangler r2 bucket cors put my-bucket --rules '[
{
"AllowedOrigins": ["https://example.com"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]'const multipart = await env.MY_BUCKET.createMultipartUpload('large-file.mp4');
// Upload parts (5MiB - 5GiB each, max 10,000 parts)
const part1 = await multipart.uploadPart(1, chunk1);
const part2 = await multipart.uploadPart(2, chunk2);
// Complete upload
const object = await multipart.complete([part1, part2]);const multipart = await env.MY_BUCKET.createMultipartUpload('large-file.mp4');
// 上传分段(每个分段5MiB - 5GiB,最多10,000个分段)
const part1 = await multipart.uploadPart(1, chunk1);
const part2 = await multipart.uploadPart(2, chunk2);
// 完成上传
const object = await multipart.complete([part1, part2]);undefinedundefined
Objects migrate when first requested. Subsequent requests served from R2.
对象会在首次被请求时迁移,后续请求直接从R2获取。wrangler r2 bucket lifecycle put my-bucket --rules '[
{
"action": {"type": "AbortIncompleteMultipartUpload"},
"filter": {},
"abortIncompleteMultipartUploadDays": 7
},
{
"action": {"type": "Transition", "storageClass": "InfrequentAccess"},
"filter": {"prefix": "archives/"},
"daysFromCreation": 90
}
]'wrangler r2 bucket lifecycle put my-bucket --rules '[
{
"action": {"type": "AbortIncompleteMultipartUpload"},
"filter": {},
"abortIncompleteMultipartUploadDays": 7
},
{
"action": {"type": "Transition", "storageClass": "InfrequentAccess"},
"filter": {"prefix": "archives/"},
"daysFromCreation": 90
}
]'wrangler r2 bucket notification create my-bucket \
--queue=my-queue \
--event-type=object-createobject-createobject-delete{
"account": "account-id",
"bucket": "my-bucket",
"object": {"key": "file.txt", "size": 1024, "etag": "..."},
"action": "PutObject",
"eventTime": "2024-01-15T12:00:00Z"
}wrangler r2 bucket notification create my-bucket \
--queue=my-queue \
--event-type=object-createobject-createobject-delete{
"account": "account-id",
"bucket": "my-bucket",
"object": {"key": "file.txt", "size": 1024, "etag": "..."},
"action": "PutObject",
"eventTime": "2024-01-15T12:00:00Z"
}references/api-reference.mdreferences/sdk-examples.mdreferences/workers-patterns.mdreferences/pricing-guide.mdreferences/api-reference.mdreferences/sdk-examples.mdreferences/workers-patterns.mdreferences/pricing-guide.md