功能与集成
Storage (R2)
基于 Cloudflare R2 的对象存储。模板内置了一个 最小实现 —— 账户页的头像上传,它是你后续做任何文件上传功能的参考蓝本。
fork 后你要改哪: 大多数场景照抄
uploadAvatar这条链路即可 —— 改src/features/storage/storage.ts里的类型/大小白名单,再按需复制一份 server fn。 部署时按需启用下面的可选绑定。
工作原理
BUCKET 是一个 Cloudflare 绑定(binding),和 DB、CACHE 一样声明在
wrangler.jsonc 里。R2 在部署环境中是可选的:没有 BUCKET 时,账户页隐藏头像上传,
上传接口返回不可用,头像读取接口返回 404。本地开发和测试使用 Miniflare 模拟的 R2,零配置即可跑。
- 写 ——
uploadAvatarserver fn(src/features/storage/actions.ts):校验类型/大小 (src/features/storage/storage.ts),以每用户一个 key 写入 R2 (avatars/<userId>—— 重复上传即覆盖,不产生孤儿对象),再把user.image指向读取路由。 - 读 —— R2 对象非公开,所以由
GET /api/avatars/<userId>(src/routes/api/avatars/$.ts)把对象流式返回,并从 R2 的httpMetadata恢复Content-Type。存储的 URL 每次上传都会加缓存击穿参数(?v=…)。 - 校验放在纯函数
storage.ts里,浏览器选择器和服务端 handler 共用同一套规则。 限制:2 MB;PNG/JPEG/WebP/GIF。
本地开发与测试
无需任何配置 —— pnpm dev 和 pnpm test 都用 miniflare 的 R2。workers 集成测试
(storage.workers.test.ts)会跑一次真实的 put/get 往返。
部署
远程环境默认不启用头像绑定 BUCKET。生产模板中的 SKILL_IMAGES 是独立的技能示例图片绑定,需创建对应的 R2 桶。
启用头像上传时,请在现有绑定数组中另外添加 BUCKET,保留已有的技能图片绑定。
R2 的免费额度不等于费用上限:超额计费,预算提醒不会停止用量。
wrangler r2 bucket create mazeseek-files # 默认(top-level)
wrangler r2 bucket create mazeseek-files-staging # staging 环境
wrangler r2 bucket create mazeseek-files-prod # production 环境在目标环境(例如 env.production)中设置:
"r2_buckets": [{ "binding": "BUCKET", "bucket_name": "mazeseek-files-prod" }]重新构建并部署后自动恢复头像上传。
扩展
- 其他文件类型 —— 复制
uploadAvatar,替换storage.ts里的白名单即可。 - 按用户/按组织配额 —— 在写入时按字节计量。商业版的
usage计量分支已备好可接入的表。 - 更大的文件 —— 多 GB 上传改用 预签名 URL,让字节流 完全绕过 Worker。