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" }),
}),
],
});
設定
| 選項 | 型別 | 說明 |
|---|---|---|
binding | string | wrangler.jsonc 中的 R2 繫結名 |
publicUrl | string | 選填的儲存桶公開 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 儲存桶上啟用公開存取:
- Cloudflare 控制台 > R2 > 你的儲存桶
- 在設定中啟用公開存取
- 將公開 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
}),
}),
],
});
設定
| 選項 | 型別 | 必填 | 說明 |
|---|---|---|---|
endpoint | string | 是 | S3 端點 URL |
bucket | string | 是 | 儲存桶名稱 |
accessKeyId | string | 否* | 存取金鑰 |
secretAccessKey | string | 否* | 私密金鑰 |
region | string | 否 | 區域(預設 "auto") |
publicUrl | string | 否 | 選填 CDN 或公開 URL |
* accessKeyId 與 secretAccessKey 必須同時提供,或同時省略。
從環境變數解析 S3 設定
s3({...}) 中省略的欄位會在行程啟動時從對應的 S3_* 環境變數讀取。這樣你可以
一次建置容器映像,啟動時注入憑證,無需重新建置。s3({...}) 中明確傳入的值始終
優先於環境變數。
| 環境變數 | 欄位 | 備註 |
|---|---|---|
S3_ENDPOINT | endpoint | 必須是合法的 http/https URL |
S3_BUCKET | bucket | |
S3_ACCESS_KEY_ID | accessKeyId | |
S3_SECRET_ACCESS_KEY | secretAccessKey | |
S3_REGION | region | 預設 "auto" |
S3_PUBLIC_URL | publicUrl | 選填 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",
}),
}),
],
});
設定
| 選項 | 型別 | 說明 |
|---|---|---|
directory | string | 檔案儲存目錄 |
baseUrl | string | 對外提供檔案的基礎 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;
}
介面一致,便於在不改應用程式碼的情況下切換後端。