存储选项

本页内容

EmDash 将上传的媒体(图片、文档、视频)存储在可配置的存储后端中。根据您的部署平台和需求进行选择。

概述

存储最适合特性
R2 BindingCloudflare Workers零配置,快速
S3任何平台签名上传,CDN 支持
Local开发环境简单的文件系统存储

Cloudflare R2 (Binding)

在部署到 Cloudflare Workers 时使用 R2 绑定以获得最快的集成。

import emdash from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

配置

选项类型描述
bindingstring来自 wrangler.jsonc 的 R2 绑定名称
publicUrlstring存储桶的可选公共 URL

设置

将 R2 绑定添加到您的 Wrangler 配置中:

wrangler.jsonc

{
  "r2_buckets": [
    {
      "binding": "MEDIA",
      "bucket_name": "emdash-media"
    }
  ]
}

wrangler.toml

[[r2_buckets]]
binding = "MEDIA"
bucket_name = "emdash-media"

公共访问

对于公共媒体 URL,在您的 R2 存储桶上启用公共访问:

  1. 转到 Cloudflare 控制面板 > R2 > 您的存储桶
  2. 在设置中启用公共访问
  3. 将公共 URL 添加到您的配置中:
storage: r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

S3 兼容存储

S3 适配器适用于 Cloudflare R2(通过 S3 API)、MinIO 和其他 S3 兼容服务。

以下配置将 EmDash 指向 S3 兼容存储桶:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: s3({
				endpoint: process.env.S3_ENDPOINT,
				bucket: process.env.S3_BUCKET,
				accessKeyId: process.env.S3_ACCESS_KEY_ID,
				secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
				region: "auto", // Optional, defaults to "auto"
				publicUrl: process.env.S3_PUBLIC_URL, // Optional CDN URL
			}),
		}),
	],
});

配置

选项类型必需描述
endpointstringS3 端点 URL
bucketstring存储桶名称
accessKeyIdstring否*访问密钥
secretAccessKeystring否*密钥
regionstring区域(默认:"auto"
publicUrlstring可选的 CDN 或公共 URL

* accessKeyIdsecretAccessKey 必须一起提供,或者都省略。

从环境变量解析 S3 配置

s3({...}) 中省略的任何字段都会在进程启动时从匹配的 S3_* 环境变量中读取。这使您可以构建一次容器镜像,并在启动时注入凭证而无需重建。s3({...}) 中的显式值始终优先于环境变量。

环境变量字段注意事项
S3_ENDPOINTendpoint必须是有效的 http/https URL
S3_BUCKETbucket
S3_ACCESS_KEY_IDaccessKeyId
S3_SECRET_ACCESS_KEYsecretAccessKey
S3_REGIONregion默认:"auto"
S3_PUBLIC_URLpublicUrl可选的 CDN 前缀

环境变量在进程启动时从 process.env 读取。这是仅限 Node 的功能。

不带参数调用 s3() 会从 S3_* 环境变量读取每个字段:

import emdash, { s3 } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			// 不带参数的 s3():所有字段来自 S3_* 环境变量
			storage: s3(),

			// 或混合:覆盖一个字段,其余来自环境
			// storage: s3({ publicUrl: "https://cdn.example.com" }),
		}),
	],
});

通过 S3 API 使用 R2

将 S3 凭证与 R2 一起使用以获得签名上传 URL 等功能:

storage: s3({
	endpoint: "https://<account-id>.r2.cloudflarestorage.com",
	bucket: "emdash-media",
	accessKeyId: process.env.R2_ACCESS_KEY_ID,
	secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
	publicUrl: "https://pub-xxxx.r2.dev",
});

在 Cloudflare 控制面板的 R2 > Manage R2 API Tokens 下生成 R2 API 凭证。

MinIO

将 S3 适配器指向带有访问凭证的 MinIO 端点:

storage: s3({
	endpoint: "https://minio.example.com",
	bucket: "emdash-media",
	accessKeyId: process.env.MINIO_ACCESS_KEY,
	secretAccessKey: process.env.MINIO_SECRET_KEY,
	publicUrl: "https://minio.example.com/emdash-media",
});

本地文件系统

使用本地存储进行开发。文件存储在磁盘上的目录中。

import emdash, { local } from "emdash/astro";

export default defineConfig({
	integrations: [
		emdash({
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
		}),
	],
});

配置

选项类型描述
directorystring文件存储的目录路径
baseUrlstring提供文件服务的基础 URL

除非您配置自定义静态文件服务器,否则 baseUrl 应与 EmDash 的媒体文件端点(/_emdash/api/media/file)匹配。

基于环境的配置

根据环境切换存储后端:

import emdash, { s3, local } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

const storage = import.meta.env.PROD
	? r2({ binding: "MEDIA" })
	: local({
			directory: "./uploads",
			baseUrl: "/_emdash/api/media/file",
		});

export default defineConfig({
	integrations: [emdash({ storage })],
});

签名上传

S3 适配器支持签名上传 URL,允许客户端直接上传到存储而无需通过您的服务器。这提高了大文件的性能。

使用 S3 适配器时签名上传是自动的。管理界面在可用时使用它们。

支持签名上传的适配器:

  • S3(包括通过 S3 API 的 R2)

不支持签名上传的适配器:

  • R2 binding(改用带有 R2 凭证的 S3 适配器)
  • Local

Storage 接口

所有存储适配器实现相同的接口:

interface Storage {
	upload(options: {
		key: string;
		body: Buffer | Uint8Array | ReadableStream;
		contentType: string;
	}): Promise<UploadResult>;

	download(key: string): Promise<DownloadResult>;
	delete(key: string): Promise<void>;
	exists(key: string): Promise<boolean>;
	list(options?: ListOptions): Promise<ListResult>;
	getSignedUploadUrl(options: SignedUploadOptions): Promise<SignedUploadUrl>;
	getPublicUrl(key: string): string;
}

这种一致性允许在不更改应用程序代码的情况下切换存储后端。