儲存選項

本頁內容

EmDash 將上傳的媒體(圖片、文件、影片)保存在可設定的後端,請依平台與需求選擇。

概覽

儲存適用情境特點
R2 繫結Cloudflare Workers零設定、速度快
S3任意平台簽章上傳、CDN 支援
本機開發簡單檔案系統儲存

Cloudflare R2(繫結)

部署至 Cloudflare Workers 時,使用 R2 繫結可最快整合。

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

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

設定

選項型別說明
bindingstringwrangler.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 及其他相容服務。

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 環境。

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

export default defineConfig({
	integrations: [
		emdash({
			// s3() with no args: all fields from S3_* environment variables
			storage: s3(),

			// Or mix: override one field, rest from environment
			// 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",
});

在控制台 R2 > Manage R2 API Tokens 產生 R2 API 憑證。

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 繫結(請改用帶 R2 憑證的 S3 配接器)
  • 本機

儲存介面

所有儲存配接器實作相同介面:

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;
}

介面一致,便於在不改應用程式碼的情況下切換後端。