R2 文件管理
TanStack Ship R2 文件管理系统,支持 Cloudflare 对象存储、文件上传管理、签名 URL 生成和审计日志。
概述
TanStack Ship 的 R2 文件管理系统提供了一套完整且生产就绪的解决方案,用于处理文件上传和资产存储,底层基于 Cloudflare R2 无服务器对象存储。从营销图片和博客媒体到可下载资源及用户上传内容,系统管理文件的全生命周期——上传、存储、访问控制和删除——并提供完整的审计追踪能力。
作为 TanStack Ship 平台的一部分,R2 文件管理模块与博客 CMS 的媒体存储、管理仪表板的文件管理以及 URL 生成 API 的资产安全交付深度集成。系统同时支持公开和签名 URL 两种访问模式,适用于广泛的内容交付场景。
设计流程
R2 文件管理系统编排从上传到存储再到访问的完整文件生命周期,每个阶段都有审计日志记录:
核心能力
文件上传系统
文件可通过多种渠道上传,每种方式都包含一致的审计日志:
- 管理界面 — 通过
/dashboard/admin/r2的 R2 管理页面上传,支持拖放和批量上传 - API 端点 — 通过
POST /api/r2/upload以编程方式上传,采用 multipart 表单数据,支持身份验证和速率限制 - 直接上传 — 使用 Cloudflare R2 S3 兼容 API 进行服务器到服务器的文件传输,适用于后端工作流
每次上传操作都会记录在 r2_uploads 数据库表中,包含完整的元数据——文件名、大小、内容类型、上传用户和精确时间戳。这为账单审计、合规检查和运维故障排除提供了可靠的审计线索。
文件管理界面
管理界面通过专用仪表板提供全面的文件管理能力:
- 文件浏览器 — 浏览所有已上传文件,图片显示缩略图预览,其他格式显示文档图标
- 搜索与筛选 — 按名称(部分匹配)、日期范围、上传者或内容类型查找文件
- 文件预览 — 直接在浏览器中查看图片、PDF 和文本文件,无需下载
- 批量操作 — 一次性选择并删除多个文件,配有确认保护机制
- 文件详情 — 查看元数据,包括存储位置、访问 URL、上传日期和文件哈希
URL 生成与访问控制
系统支持多种 URL 生成策略,在可访问性和安全性之间取得平衡:
- 公开 URL — 直接 R2 公开存储桶 URL,用于提供图片、CSS、JavaScript 和其他公共资产服务。适用于营销内容和博客媒体等无须限制访问的场景
- API 访问 — 通过
GET /api/r2/files/$key获取文件,经过服务器端身份验证和授权检查 - 签名 URL — 限时预签名 URL,用于私有文件访问。有效期按请求可配置,确保敏感文件在允许临时分享的同时得到保护
签名 URL 机制使用 Cloudflare R2 内置的预签名能力,生成经加密验证的 URL,在可配置的时间后自动过期——通常临时访问设为 1 小时,批处理工作流可设为更长。
示例 — 在 React 中获取签名 URL:
import { useQuery } from '@tanstack/react-query'
function SecureDownload({ fileKey }: { fileKey: string }) {
const { data, isLoading } = useQuery({
queryKey: ['signed-url', fileKey],
queryFn: async () => {
const res = await fetch(`/api/r2/sign/${fileKey}`)
if (!res.ok) throw new Error('获取签名 URL 失败')
return res.json() as Promise<{ signedUrl: string; expiresIn: number }>
},
})
if (isLoading) return <div>正在准备下载...</div>
return (
<a href={data?.signedUrl} download>
下载文件
</a>
)
}
设计理念
审计优先操作
每个文件操作——上传、访问、删除——都记录在审计日志中,包含完整的元数据:文件名、大小、内容类型、用户归因和时间戳。这种审计优先的理念意味着系统提供了所有文件生命周期事件的不可变记录,支持合规要求、账单验证和运维问题排查。审计表是所有文件相关活动的唯一真实来源。
双重访问模型
系统支持公开和签名 URL 两种访问模式,适用于不同的使用场景。公开 URL 以零开销服务静态资产(图片、CSS、可下载资源),而签名 URL 为私有文件提供可配置过期时间的限时访问。这种双重模型让平台运营者可以精细控制资产安全性——敏感文档需要身份验证并自动过期,营销资产则通过 R2 的边缘网络全球分发。
默认无服务器
基于 Cloudflare R2 构建,文件管理系统继承了无服务器优势:零出站流量费用、通过边缘缓存自动全球分发、无需基础设施管理。与传统 AWS S3 方案按每 GB 收取数据传输费不同,R2 在保持 100% S3 API 兼容性的同时完全消除了出站流量费用——使其成为高流量应用、媒体交付和多区域工作负载的高性价比替代方案。文件存储在 Cloudflare 的全球网络中,从离用户最近的边缘节点提供服务。这种架构消除了管理文件服务器和 CDN 配置的运维负担,同时提供企业级的性能和可靠性。
最佳实践
文件大小和类型验证
始终在上传处理器中配置文件大小限制和允许的 MIME 类型。系统通过环境变量支持可配置的限制——设置 R2_MAX_FILE_SIZE 为所需的最大值(默认 50MB),并根据应用需求限制上传类型。这可以防止存储耗尽并阻止恶意文件上传。
签名 URL 过期时间管理
根据使用场景选择合适的签名 URL 过期时间:敏感文档的一次性下载使用短有效期(5-15 分钟),批处理工作流使用较长有效期(1-24 小时)。切勿使用无限期有效期的签名 URL,否则将破坏安全优势。
存储组织策略
采用逻辑化的 key 前缀策略来组织 R2 中的文件。推荐模式包括:
uploads/{年}/{月}/{uuid}-{文件名}— 用户上传文件blog/{年}/{slug}/{文件名}— 博客媒体marketing/{活动名称}/{文件名}— 营销资产
这种命名约定使存储桶保持有序,支持按前缀高效列出文件,并防止不同文件类别之间的 key 冲突。
定期审计审查
定期检查 r2_uploads 审计表,识别孤立或未使用的文件。考虑实施生命周期策略,自动标记超过可配置阈值的旧文件以供审查,帮助控制存储成本并维护数据健康。
常见问题
R2 系统支持哪些文件类型? 默认情况下,系统接受常见文件类型,包括图片(JPEG、PNG、WebP、GIF、SVG)、文档(PDF、DOCX、TXT)和媒体文件(MP4、MP3)。允许的 MIME 类型可通过上传处理器中间件的配置进行扩展。
如何为私有文件生成签名 URL?
携带身份验证标头调用 GET /api/r2/sign/$key。响应默认包含有效期为 1 小时的预签名 URL。你可以通过传递 expiresIn 查询参数(以秒为单位)来自定义过期时间。
能否在 R2 中将文件组织到文件夹中?
Cloudflare R2 使用扁平化的键值存储模型,但你可以通过使用基于前缀的 key 命名(例如 blog/2024/my-post/image.jpg)来模拟文件夹结构。管理仪表板按前缀分组显示文件以实现组织化展示。
存储文件数量是否有限制? Cloudflare R2 对可存储的对象数量没有限制。但应注意账户的存储配额,并在上传处理器中设置适当的文件大小限制,以防止意外费用。
系统如何处理重复文件名? 每个上传的文件在 R2 中都会收到一个唯一的 key,通常包含 UUID 或时间戳前缀以防止冲突。原始文件名保留在数据库元数据中用于显示。
能否从管理界面批量删除文件? 可以。管理界面支持选择多个文件并在一次操作中全部删除。系统会删除 R2 对象并移除相应的数据库审计条目。
配置
在 .dev.vars 中配置以下环境变量:
R2_BUCKET_NAME=your-bucket
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_PUBLIC_URL=https://pub-xxx.r2.dev
R2_MAX_FILE_SIZE=52428800
R2 存储桶绑定还必须在 wrangler.jsonc 中配置:
{
"r2_buckets": [
{ "binding": "R2_BUCKET", "bucket_name": "your-bucket" }
]
}
本地开发时,系统提供模拟模式,无需实际存储桶配置即可模拟 R2 存储。使用 npm run dev 以启用模拟存储的开发模式启动。
集成点
R2 文件管理系统与以下 TanStack Ship 平台模块集成: