存储服务
配置 Cloudflare R2 对象存储,管理用户上传的头像与文件
存储服务
EasyStarter 使用 Cloudflare R2 作为对象存储服务,用于上传和管理用户文件。目前内置支持以下两种上传类型:
| 上传类型 | 说明 | 文件大小限制 |
|---|---|---|
avatar | 用户头像 | 5 MB |
attachment | 附件文件(图片、PDF、文本) | 25 MB |
创建 R2 Bucket
官方文档:R2 Getting started
方式一:通过 Cloudflare Dashboard
- 登录 Cloudflare Dashboard
- 进入 R2 Object Storage
- 点击 Create bucket
- 输入 bucket 名称,例如
your-app-bucket - 选择地域(推荐 Automatic)
- 点击 Create bucket
方式二:通过 Wrangler CLI
pnpm wrangler r2 bucket create your-app-bucket配置 wrangler.jsonc
在 apps/server/wrangler.jsonc 的 r2_buckets 字段中填入你的 bucket 名称:
"r2_buckets": [
{
"binding": "STORAGE",
"bucket_name": "your-app-bucket"
}
],binding固定为STORAGE,这是 Worker 内部访问 R2 的变量名,不要修改bucket_name改为你在 R2 创建的 bucket 名称
开启公开访问并获取 R2_PUBLIC_URL
文件上传后,需要通过公开 URL 访问。推荐使用 R2 的 Public Access 功能。
通过 Cloudflare Dashboard 开启(推荐)
- 进入你的 R2 bucket 详情页
- 点击 Settings 标签
- 在 Public Access 区域点击 Allow Access
- 开启后会自动生成一个公开 URL,格式为:
https://pub-xxxxxxxx.r2.dev
这个 URL 就是 R2_PUBLIC_URL。
自定义域名(可选)
也可以在 bucket Settings → Custom Domains 绑定自定义域名,例如 https://cdn.yourdomain.com,绑定后使用自定义域名作为 R2_PUBLIC_URL。
填入 R2_PUBLIC_URL 环境变量
R2_PUBLIC_URL 需要填入两个环境变量文件:
本地开发(apps/server/.dev.vars):
R2_PUBLIC_URL=https://pub-xxxxxxxx.r2.dev生产部署(apps/server/.env.production):
R2_PUBLIC_URL=https://pub-xxxxxxxx.r2.dev.env.production 用于通过 pnpm run secrets:bulk:production 批量推送到 Cloudflare Workers 的 Secrets,不会直接参与构建。
配置存储参数(可选)
存储相关参数在 packages/app-config/src/app-config.ts 的 common.storage 字段中定义,可按需调整:
storage: {
provider: "r2",
publicPath: "/api/storage", // 文件访问的 API 路径前缀
keyPrefixes: {
avatar: "avatars", // 头像文件存储路径前缀
attachment: "attachments", // 附件文件存储路径前缀
},
fallbackPrefix: "files", // 未指定类型时的兜底前缀
allowedTypes: {
avatar: ["image/jpeg", "image/png", "image/gif", "image/webp"],
attachment: ["image/jpeg", "image/png", "image/gif", "image/webp",
"application/pdf", "text/plain"],
},
maxFileSizes: {
avatar: 5 * 1024 * 1024, // 5 MB
attachment: 25 * 1024 * 1024, // 25 MB
},
},扩展其他存储服务
EasyStarter 的存储层基于 StorageProvider 接口设计,只需四步即可接入任意存储服务(如 AWS S3、Cloudflare R2、MinIO 等)。
第一步:扩展服务商类型
假设以 S3 为例,在 packages/app-config/src/types.ts 中,将新服务商 key 追加到 SUPPORTED_STORAGE_PROVIDERS:
export const SUPPORTED_STORAGE_PROVIDERS = ["r2", "s3"] as const;第二步:实现 Provider
在 apps/server/src/storage/providers/ 下新建文件,实现 StorageProvider 接口:
import type { StorageProvider } from "../types";
export function createS3StorageProvider({ client, bucket }: {
client: S3Client;
bucket: string;
}): StorageProvider {
return {
async put(key, data, options) {
// 调用 S3 SDK 上传文件
},
async get(key) {
// 调用 S3 SDK 下载文件
},
async head(key) {
// 调用 S3 SDK 获取元数据
},
async delete(key) {
// 调用 S3 SDK 删除文件
},
};
}第三步:注册到存储服务商中
在 apps/server/src/storage/index.ts 的 providers 对象中注册新 Provider:
import { createS3StorageProvider } from "./providers/s3";
const providers: Record<StorageProviderKey, StorageProvider> = {
r2: createR2StorageProvider({ bucket: storage }),
s3: createS3StorageProvider({ client: s3Client, bucket: "your-bucket" }),
};第四步:切换配置
在 packages/app-config/src/app-config.ts 中将 storage.provider 改为新服务商的 key:
storage: {
provider: "s3", // 切换到新服务商
// ...其余配置保持不变
},完成后,所有文件上传、下载、删除操作都会自动通过新 Provider 执行,无需修改业务代码。