Signatur
Beschreibung
formData() gehört zum Body-Mixin, das Request und Response gemeinsam haben. Die Methode liest den Datenstrom des Anfragekörpers bis zum Ende und wandelt ihn in ein FormData-Objekt um. Unterstützt werden die Inhaltstypen multipart/form-data und application/x-www-form-urlencoded. Welches Format vorliegt, erkennt die Methode am Content-Type-Header der Anfrage.
Im Browser braucht man sie selten. Richtig nützlich ist sie serverseitig und in Service Workern: in einem fetch-Event-Handler, in Edge-Funktionen (Cloudflare Workers, Deno, Vercel), in Route-Handlern von Next.js, Remix oder SvelteKit sowie in Node.js ab Version 18 mit der eingebauten Fetch-API. Dort lassen sich abgeschickte HTML-Formulare, auch mit Datei-Uploads, ohne zusätzliche Bibliothek auswerten.
Der Körper eines Requests lässt sich nur einmal lesen. Nach dem Aufruf ist request.bodyUsed auf true gesetzt. Jeder weitere Leseversuch mit json(), text() oder erneut formData() scheitert mit einem TypeError. Wer den Körper mehrfach braucht, erstellt vorher mit request.clone() eine Kopie.
Rückgabewert
FormData-Objekt erfüllt wird. Hochgeladene Dateien erscheinen darin als File-Objekte, alle anderen Felder als Strings. Das Promise wird mit einem TypeError abgelehnt, wenn der Körper schon gelesen wurde, der Content-Type fehlt oder nicht passt oder die Daten nicht geparst werden können.Beispiele
Request mit FormData erzeugen und wieder auslesen
const fd = new FormData();
fd.append('name', 'Anna');
fd.append('sprache', 'de');
const request = new Request('https://example.com/api', {
method: 'POST',
body: fd // Content-Type multipart/form-data wird automatisch gesetzt
});
const daten = await request.formData();
console.log(daten.get('name'));
console.log([...daten.keys()]);
URL-kodierte Daten parsen
const request = new Request('https://example.com/login', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'benutzer=max&passwort=geheim123'
});
const form = await request.formData();
const { benutzer } = Object.fromEntries(form);
console.log(benutzer);
Datei-Upload in einem Route-Handler (Web-Standard, z. B. Next.js / Deno / Workers)
export const POST = async (request) => {
let form;
try {
form = await request.formData();
} catch {
return new Response('Ungültiger Formularkörper', { status: 400 });
}
const titel = form.get('titel') ?? '';
const datei = form.get('datei');
if (!(datei instanceof File)) {
return new Response('Keine Datei übermittelt', { status: 400 });
}
const bytes = await datei.arrayBuffer();
return Response.json({ titel, dateiname: datei.name, groesse: bytes.byteLength });
};
Service Worker: Körper klonen, um ihn doppelt zu nutzen
self.addEventListener('fetch', (event) => {
const { request } = event;
if (request.method !== 'POST' || !request.url.endsWith('/kontakt')) return;
event.respondWith((async () => {
// Kopie für die Auswertung, das Original geht ans Netzwerk
const form = await request.clone().formData();
console.log('E-Mail:', form.get('email'));
return fetch(request);
})());
});
// Wichtig · Fallstricke
- Einmal lesbar: Nach dem ersten Aufruf ist
bodyUsed === true. Ein zweiter Leseversuch wirft einenTypeError. Deshalb vorherrequest.clone()verwenden. - Content-Type ist Pflicht: Fehlt der Header oder hat er einen anderen Wert, etwa
application/json, wird das Promise abgelehnt. Beimultipart/form-datamuss außerdem der Parameterboundarystimmen. Setzen Sie diesen Header nie von Hand, wenn der Körper einFormData-Objekt ist. Den Header setzt der Browser bzw. die Laufzeit automatisch, samt korrekter Boundary. - Speicher: Der gesamte Körper wird in den Speicher geladen, auch große Dateien. Bei großen Uploads besser direkt mit
request.bodyals Stream arbeiten oder eine Größenobergrenze prüfen, z. B. über den HeaderContent-Length. - Sicherheit: Formularwerte sind Eingaben des Nutzers. Prüfen und validieren Sie Typ, Länge und Dateityp (
file.typelässt sich fälschen), bevor Sie die Werte speichern oder als HTML ausgeben (Gefahr von XSS). - Kompatibilität: Unterstützt von allen modernen Browsern sowie Node.js 18+ (undici), Deno, Bun und Cloudflare Workers. Ältere Node-Versionen ohne eingebautes
fetchkennen die Methode nicht. form.get()gibtnullzurück, wenn das Feld fehlt. Bei mehrfach vorkommenden Feldern liefert erstgetAll()alle Werte.