六维教程

预签名 URL

公开访问是把整个 Bucket 暴露出去,粒度太粗。有些场景只需要让某个对象在短时间内可访问,比如发一个下载链接给客户,有效期一天就失效。这种临时授权用预签名 URL 最合适。

什么是预签名 URL

预签名 URL 是把 S3 签名直接拼到 URL 查询参数里生成的链接。拿着这个链接的人不需要 Access Key,浏览器直接打开就能下载或上传对象。

它的核心机制是,程序用密钥按签名算法计算出一个签名值,连同过期时间一起放进 URL。R2 收到请求时验签,签名有效且没过期就放行。

对比项 公开 Bucket 预签名 URL
访问范围 整个 Bucket 所有对象 单个对象
有效期 永久 自定义,可短至几秒
鉴权方式 URL 内嵌签名
适合场景 公开资源站 临时下载、客户端直传

生成下载链接

用 AWS SDK v3 的 getSignedUrl 方法生成下载链接。先装 presigner

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

生成一个有效期 1 小时的下载链接

import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({
  region: "auto",
  endpoint: "https://你的账户ID.r2.cloudflarestorage.com",
  credentials: {
    accessKeyId: "你的AccessKeyId",
    secretAccessKey: "你的SecretAccessKey",
  },
});

const downloadUrl = await getSignedUrl(
  s3,
  new GetObjectCommand({
    Bucket: "my-assets",
    Key: "reports/2026-q3.pdf",
  }),
  { expiresIn: 3600 } // 单位秒,1 小时
);

console.log(downloadUrl);
// https://xxx.r2.cloudflarestorage.com/my-assets/reports/2026-q3.pdf?X-Amz-...

把这个 URL 发给客户端,浏览器直接打开就能下载 reports/2026-q3.pdf,一小时后自动失效。

生成上传链接

预签名 URL 不仅能下载,还能让客户端直接上传到 R2,文件不经过自己的服务器,省带宽省算力。

生成上传链接用 PutObjectCommand

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const uploadUrl = await getSignedUrl(
  s3,
  new PutObjectCommand({
    Bucket: "my-assets",
    Key: "uploads/user-42/avatar.jpg",
    ContentType: "image/jpeg",
  }),
  { expiresIn: 600 } // 10 分钟
);

前端拿到这个 URL 后用 PUT 方法直接上传文件

const file = fileInput.files[0];

await fetch(uploadUrl, {
  method: "PUT",
  body: file,
  headers: {
    "Content-Type": file.type,
  },
});

这种模式叫客户端直传,浏览器绕过后端直接把文件写到 R2,后端只负责签发 URL。对大文件、高并发的上传场景非常实用。

Python boto3 生成

Python 端用 boto3 同样能生成预签名 URL

import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://你的账户ID.r2.cloudflarestorage.com",
    aws_access_key_id="你的AccessKeyId",
    aws_secret_access_key="你的SecretAccessKey",
    region_name="auto",
)

# 下载链接
download_url = s3.generate_presigned_url(
    "get_object",
    Params={"Bucket": "my-assets", "Key": "reports/2026-q3.pdf"},
    ExpiresIn=3600,
)

# 上传链接
upload_url = s3.generate_presigned_url(
    "put_object",
    Params={
        "Bucket": "my-assets",
        "Key": "uploads/user-42/avatar.jpg",
        "ContentType": "image/jpeg",
    },
    ExpiresIn=600,
)

过期时间设计

过期时间 expiresIn 怎么定要分场景

场景 建议过期时间 原因
邮件下载链接 1 到 7 天 给用户足够时间收到并打开
网页内嵌图片 1 小时 页面刷新就重新签发
客户端上传 5 到 15 分钟 足够完成一次上传,过期即拒
临时分享 几分钟 短时窗口,泄露风险低

几个细节要注意。

第一,过期时间是签发时刻算起的,不是从首次访问开始。链接生成后 1 小时失效,不管期间有没有人访问过。

第二,链接一旦签发无法主动吊销。要紧急撤回只能删除对象本身,或轮换 Access Key 让旧签名失效。

第三,预签名 URL 里不含密钥明文,只有签名结果,泄露后到过期前都能用。所以 HTTPS 传输仍然必要,别在日志里记录完整 URL。

小结

预签名 URL 把签名嵌入链接,实现单对象、有时效的临时访问。下载链接用于分发,上传链接用于客户端直传,过期时间按场景定。下一篇讲 R2 和 Workers 的深度集成,在边缘直接读写对象。

上一篇 公开访问与自定义域名
下一篇 与 Workers 绑定集成

上一篇
公开访问与自定义域名
下一篇
与 Workers 绑定集成