Medienspeicher wählen

Auf dieser Seite

Wählen Sie einen Speicheradapter für hochgeladene Medien. Eine Datenbanksicherung enthält Medienmetadaten, nicht die gespeicherten Dateien, sichern Sie also das Speicher-Backend separat.

Übersicht

SpeicherVerwenden wennSignierte Uploads
R2 BindingDie Website läuft auf Cloudflare WorkersNein
S3Eine Node.js-Website nutzt AWS S3, R2’s S3 API, MinIO oder kompatiblen SpeicherJa
LokalEine Node.js-Website hat ein beschreibbares persistentes VolumeNein

Cloudflare R2 Binding

Verwenden Sie den R2-Binding-Adapter auf Cloudflare Workers. Das Binding stellt Zugriff zur Laufzeit bereit, sodass die Website keine R2-Zugriffsschlüssel benötigt.

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

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

Konfiguration

OptionTypBeschreibung
bindingstringR2-Binding-Name aus wrangler.jsonc
publicUrlstringOptionale öffentliche URL für den Bucket

Einrichtung

Fügen Sie das R2-Binding zu Ihrer Wrangler-Konfiguration hinzu:

wrangler.jsonc

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

wrangler.toml

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

Öffentlicher Zugriff

Um Medien von einem öffentlichen Bucket bereitzustellen, verbinden Sie eine benutzerdefinierte Domain mit der Cloudflare API und setzen Sie deren Origin als publicUrl. Cloudflares r2.dev-Entwicklungs-URL ist ratenbegrenzt und nicht für Produktionstraffic gedacht.

storage: r2({
	binding: "MEDIA",
	publicUrl: "https://media.example.com",
});

Wenn derselbe Bucket automatische JSON-Backups speichert, kann ein öffentlicher Bucket-Origin Objekte unter backups/ offenlegen. Verwenden Sie einen privaten Bucket und EmDashs Medienroute oder beschränken Sie den öffentlichen Origin auf Medienobjekte. Siehe Backups.

S3-kompatibler Speicher

Der S3-Adapter funktioniert unter Node.js mit Cloudflare R2’s S3 API, AWS S3, MinIO und kompatiblen Diensten.

Die folgende Konfiguration löst Endpoint, Bucket, Credentials, Region und optionale öffentliche URL aus S3_*-Variablen auf, wenn der Node.js-Prozess startet:

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

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

Konfiguration

OptionTypErforderlichBeschreibung
endpointstringjaS3-Endpoint-URL
bucketstringjaBucket-Name
accessKeyIdstringnein*Zugriffsschlüssel
secretAccessKeystringnein*Geheimer Schlüssel
regionstringneinRegion (Standard: "auto")
publicUrlstringneinOptionale CDN- oder öffentliche URL

* Sowohl accessKeyId als auch secretAccessKey müssen zusammen angegeben oder beide weggelassen werden.

S3-Konfiguration aus Umgebungsvariablen auflösen

Jedes in s3({...}) ausgelassene Feld wird beim Prozessstart aus der entsprechenden S3_*-Umgebungsvariable gelesen. So können Sie ein Container-Image einmal bauen und Credentials beim Start injizieren, ohne neu zu bauen. Explizite Werte in s3({...}) haben immer Vorrang vor Umgebungsvariablen.

UmgebungsvariableFeldHinweise
S3_ENDPOINTendpointMuss eine gültige http/https-URL sein
S3_BUCKETbucket
S3_ACCESS_KEY_IDaccessKeyId
S3_SECRET_ACCESS_KEYsecretAccessKey
S3_REGIONregionStandard: "auto"
S3_PUBLIC_URLpublicUrlOptionales CDN-Präfix

Umgebungsvariablen werden beim Prozessstart aus process.env gelesen. Dies ist eine reine Node-Funktion.

Der Aufruf von s3() ohne Argumente liest jedes Feld aus den S3_*-Umgebungsvariablen:

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

export default defineConfig({
	integrations: [
		emdash({
			// s3() ohne Argumente: alle Felder aus S3_*-Umgebungsvariablen
			storage: s3(),

			// Oder mischen: ein Feld überschreiben, Rest aus der Umgebung
			// storage: s3({ publicUrl: "https://cdn.example.com" }),
		}),
	],
});

R2 über S3 API

Verwenden Sie den S3-Adapter unter Node.js, wenn direkte signierte Uploads zu R2 erforderlich sind. Erstellen Sie begrenzte R2 API-Credentials mit der Cloudflare API oder CLI und setzen Sie dann die folgenden Laufzeitvariablen:

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

Bewahren Sie die echten Werte im Secret Manager der Node.js-Hosting-Plattform auf. Die öffentliche URL ist optional und ersetzt nicht den S3 API-Endpoint, der für Uploads verwendet wird.

MinIO

Richten Sie die gleichen Laufzeitvariablen auf MinIO. Setzen Sie S3_ENDPOINT auf den MinIO API-Origin, S3_BUCKET auf den Bucket-Namen und die beiden Credential-Variablen auf einen begrenzten MinIO-Zugriffsschlüssel. Setzen Sie S3_PUBLIC_URL nur, wenn dieser Origin die Objekte des Buckets öffentlich bereitstellt.

Lokales Dateisystem

Verwenden Sie lokalen Speicher für die Entwicklung oder einen einzelnen Node.js-Server mit persistenter Festplatte. Dateien werden in einem Verzeichnis auf dieser Festplatte gespeichert.

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

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

Konfiguration

OptionTypBeschreibung
directorystringVerzeichnispfad für Dateispeicher
baseUrlstringBasis-URL zum Bereitstellen von Dateien

Die baseUrl sollte mit EmDashs Medien-Datei-Endpoint (/_emdash/api/media/file) übereinstimmen, es sei denn, Sie konfigurieren einen benutzerdefinierten statischen Dateiserver.

Separaten Speicher für verschiedene Umgebungen verwenden

Die folgende Konfiguration verwendet während der Entwicklung ein lokales Verzeichnis und R2 im Cloudflare-Produktions-Build:

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 })],
});

Signierte Uploads

Der S3-Adapter unterstützt signierte Upload-URLs, die es Clients ermöglichen, direkt in den Speicher hochzuladen, ohne über Ihren Server zu gehen. Dies verbessert die Leistung bei großen Dateien.

Signierte Uploads sind automatisch, wenn der S3-Adapter verwendet wird. Die Admin-Oberfläche nutzt sie, wenn verfügbar.

Adapter, die signierte Uploads unterstützen:

  • S3 (einschließlich R2 über S3 API)

Adapter, die keine signierten Uploads unterstützen:

  • R2 Binding (verwenden Sie stattdessen den S3-Adapter mit R2-Credentials)
  • Lokal

Speicher-Interface

Alle Speicheradapter implementieren das gleiche Interface:

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

	download(key: string, options?: DownloadOptions): 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;
}

Diese Konsistenz ermöglicht den Wechsel von Speicher-Backends, ohne den Anwendungscode zu ändern.

Byte-Bereiche

Die Medienroute /_emdash/api/media/file/ beantwortet HTTP-Range-Anfragen. Safari spielt Videos nur von Servern ab, die sie unterstützen, und andere Browser nutzen sie zum Vor- und Zurückspulen. Die Route übergibt den angeforderten Bereich als options.range an download(); das ist entweder { offset, length } oder { suffix } für die letzten suffix Bytes. length entfällt bei einem offenen Bereich wie bytes=500-.

Ein Adapter, der Bereiche unterstützt, liefert den Teil des angeforderten Bereichs, der innerhalb der Datei liegt, und setzt im Ergebnis range: { offset, length }, um ihn zu beschreiben. size ist immer die Größe der gesamten Datei. Kann ein Adapter einen Bereich nicht bedienen, auch wenn dieser hinter dem Dateiende beginnt, liefert er die ganze Datei ohne range zurück. Die Route antwortet dann mit der ganzen Datei oder, wenn der Bereich hinter dem Ende beginnt, mit 416 Range Not Satisfiable.

Die Adapter für R2, S3 und das lokale Dateisystem unterstützen Bereiche. Für einen benutzerdefinierten Adapter ist die Bereichsunterstützung optional: Ignoriert er options, erhalten Bereichsanfragen die ganze Datei oder 416, wenn der Bereich hinter dem Ende beginnt.