Start · Sprachen · JavaScript · Referenz · Request.bytes()

Request.bytes()

Methode

Liest den Körper einer <code>Request</code> vollständig ein und gibt ein Promise zurück, das mit einem <code>Uint8Array</code> erfüllt wird.

seit JavaScript Baseline 2025: Chrome 132+, Firefox 128+, Safari 1 Kategorie: webapi

Signatur

Request.prototype.bytes()

Beschreibung

Die Methode bytes() gehört zum Body-Mixin, das Request und Response gemeinsam nutzen. Sie liest den Datenstrom des Anfragekörpers bis zum Ende und liefert die Rohdaten als Uint8Array. Im Vergleich zu arrayBuffer() sparst du dir damit den Zwischenschritt new Uint8Array(await request.arrayBuffer()).

Nützlich ist das vor allem dort, wo du eine Anfrage empfängst oder abfängst, statt sie selbst zu senden: in einem Service Worker im fetch-Event, in serverseitigen Laufzeitumgebungen wie Node.js, Deno, Bun oder Cloudflare Workers, oder in Tests, in denen du ein selbst gebautes Request-Objekt prüfen willst. Typische Anwendungen sind Prüfsummen und Signaturen (z. B. HMAC-Prüfung bei Webhooks), das Weiterleiten von Binär-Uploads und das Auswerten eigener Binärformate.

Der Körper lässt sich nur einmal lesen. Danach steht request.bodyUsed auf true und jeder weitere Leseversuch (bytes(), text(), json() …) schlägt fehl. Wenn du den Körper mehrfach brauchst, zum Beispiel um die Anfrage nach dem Prüfen noch weiterzuleiten, lies ihn vorher über request.clone() aus.

Rückgabewert

Typ
Promise<Uint8Array>
Beschreibung
Ein Promise, das mit einem Uint8Array mit dem vollständigen Anfragekörper erfüllt wird. Hat die Anfrage keinen Körper (body === null), ist das Array leer (Länge 0).

Beispiele

Körper einer selbst erstellten Anfrage als Bytes lesen

const request = new Request('https://example.com/api/upload', {
  method: 'POST',
  body: 'Hallo'
});

const bytes = await request.bytes();
console.log(bytes);
console.log(request.bodyUsed);
Uint8Array(5) [72, 97, 108, 108, 111] true

Webhook-Signatur (SHA-256) über den Rohkörper berechnen

// z. B. in einem Cloudflare Worker, Deno oder Bun
const sha256Hex = async (data) => {
  const hash = await crypto.subtle.digest('SHA-256', data);
  return [...new Uint8Array(hash)]
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
};

const handleWebhook = async (request) => {
  // Klon lesen, damit das Original weitergereicht werden kann
  const raw = await request.clone().bytes();
  const digest = await sha256Hex(raw);
  const expected = request.headers.get('x-body-sha256');

  if (digest !== expected) {
    return new Response('Ungültige Signatur', { status: 401 });
  }
  const payload = await request.json();
  return Response.json({ ok: true, event: payload.event });
};

// Test
const body = JSON.stringify({ event: 'order.created' });
const hash = await sha256Hex(new TextEncoder().encode(body));
const res = await handleWebhook(new Request('https://example.com/hook', {
  method: 'POST',
  headers: { 'x-body-sha256': hash },
  body
}));
console.log(res.status, await res.json());
200 { ok: true, event: 'order.created' }

Binär-Upload im Service Worker mit Rückfall auf arrayBuffer()

const readBytes = async (req) =>
  typeof req.bytes === 'function'
    ? req.bytes()
    : new Uint8Array(await req.arrayBuffer());

self.addEventListener('fetch', (event) => {
  const { request } = event;
  if (request.method !== 'PUT' || !request.url.endsWith('/upload')) return;

  event.respondWith((async () => {
    const data = await readBytes(request.clone());
    // Magic Number prüfen: PNG beginnt mit 0x89 0x50 0x4E 0x47
    const isPng = data[0] === 0x89 && data[1] === 0x50 &&
                  data[2] === 0x4e && data[3] === 0x47;
    if (!isPng) {
      return new Response('Nur PNG erlaubt', { status: 415 });
    }
    return fetch(request);
  })());
});

// Wichtig · Fallstricke

  • Nur einmal lesbar: Wurde der Körper schon gelesen (bodyUsed === true) oder ist der Datenstrom gesperrt, wird das Promise mit einem TypeError abgelehnt. Vorher request.clone() verwenden, und zwar bevor du anfängst zu lesen.
  • Speicherbedarf: Der gesamte Körper landet im Arbeitsspeicher. Große Uploads verarbeitest du besser als Datenstrom über request.body (ReadableStream). Lässt sich der Puffer nicht anlegen, wird das Promise mit einem RangeError abgelehnt.
  • Abbruch: Wurde die Anfrage mit einem AbortSignal erstellt und dieses Signal abgebrochen, wird das Promise mit einer AbortError-DOMException abgelehnt.
  • Kompatibilität: Die Methode ist relativ neu (Firefox 128, Safari 18, Chrome 132). Für ältere Umgebungen per Feature-Erkennung auf new Uint8Array(await request.arrayBuffer()) zurückfallen.
  • Für Text ist text() besser geeignet, weil es automatisch als UTF-8 dekodiert. bytes() liefert die unveränderten Rohbytes, und genau die brauchst du für Signaturen.