為上傳的媒體選擇一個儲存配接器。資料庫備份包含媒體中繼資料而非儲存的檔案,因此請單獨備份儲存後端。
概覽
| 儲存 | 使用場景 | 簽章上傳 |
|---|---|---|
| R2 繫結 | 站點執行在 Cloudflare Workers 上 | 否 |
| S3 | Node.js 站點使用 AWS S3、R2 的 S3 API、MinIO 或相容儲存 | 是 |
| 本機 | Node.js 站點有一個可寫的持久磁碟區 | 否 |
Cloudflare R2 繫結
在 Cloudflare Workers 上使用 R2 繫結配接器。繫結在執行時提供存取,因此站點不需要 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" 公開存取
要從公開儲存桶提供媒體,使用 Cloudflare API 連接自訂網域,然後將其來源設定為 publicUrl。Cloudflare 的 r2.dev 開發 URL 有速率限制,不適用於正式流量。
storage: r2({
binding: "MEDIA",
publicUrl: "https://media.example.com",
});
如果同一儲存桶儲存自動 JSON 備份,公開儲存桶來源可能會暴露 backups/ 下的物件。請使用私有儲存桶和 EmDash 的媒體路由,或將公開來源限制為媒體物件。參見備份。
S3 相容儲存
S3 配接器在 Node.js 上與 Cloudflare R2 的 S3 API、AWS S3、MinIO 和相容服務一起工作。
以下設定在 Node.js 程序啟動時從 S3_* 變數解析端點、儲存桶、憑證、區域和可選的公開 URL:
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: s3(),
}),
],
});
設定
| 選項 | 型別 | 必要 | 描述 |
|---|---|---|---|
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 的功能。
呼叫不帶引數的 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
當需要直接簽章上傳到 R2 時,在 Node.js 上使用 S3 配接器。使用 Cloudflare API 或 CLI 建立範圍受限的 R2 API 憑證,然後設定以下執行時變數:
S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
S3_BUCKET=emdash-media
S3_ACCESS_KEY_ID=<r2-access-key-id>
S3_SECRET_ACCESS_KEY=<r2-secret-access-key>
S3_REGION=auto
S3_PUBLIC_URL=https://media.example.com
將真實值保存在 Node.js 託管平台的密鑰管理器中。公開 URL 是可選的,不會取代用於上傳的 S3 API 端點。
MinIO
將相同的執行時變數指向 MinIO。將 S3_ENDPOINT 設為 MinIO API 來源,S3_BUCKET 設為儲存桶名稱,兩個憑證變數設為範圍受限的 MinIO 存取金鑰。僅當該來源公開提供儲存桶物件時才設定 S3_PUBLIC_URL。
本機檔案系統
使用本機儲存進行開發或用於具有持久磁碟的單一 Node.js 伺服器。檔案儲存在該磁碟上的目錄中。
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) 匹配,除非你設定了自訂靜態檔案伺服器。
為不同環境使用不同的儲存
以下設定在開發期間使用本機目錄,在 Cloudflare 正式建置中使用 R2:
import emdash, { 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;
}
這種一致性允許在不變更應用程式碼的情況下切換儲存後端。