Einen String kodieren und dekodieren
Buffer.from(string, "utf8") wandelt Text in UTF-8-Bytes um, und .toString("base64") kodiert sie. Das Dekodieren besteht aus denselben zwei Aufrufen in umgekehrter Richtung.
const enc = Buffer.from("héllo wörld", "utf8").toString("base64");
console.log(enc); // aMOpbGxvIHfDtnJsZA==
console.log(Buffer.from(enc, "base64").toString("utf8")); // héllo wörld
"utf8" ist bei beiden Aufrufen der Standard, aber ausgeschrieben ist die Absicht offensichtlich. Buffer ist eine Unterklasse von Uint8Array, ein einfaches Uint8Array muss also umhüllt werden: u8.toString("base64") ignoriert das Argument und liefert "104,105", während Buffer.from(u8).toString("base64") den Wert aGk= liefert.
URL-sicheres Base64 (base64url)
Node hat eine eigene Kodierung für das URL-sichere Alphabet. Sie schreibt nie Padding:
Buffer.from("<<???>>").toString("base64"); // PDw/Pz8+Pg==
Buffer.from("<<???>>").toString("base64url"); // PDw_Pz8-Pg
Buffer.from("PDw_Pz8-Pg", "base64url").toString(); // <<???>>
Will ein Empfänger URL-sicheres Base64 mit Padding, hängen Sie es selbst an: s + "=".repeat((4 - s.length % 4) % 4).
Beim Dekodieren ist Node nachsichtig: Sowohl "base64" als auch "base64url" akzeptieren beide Alphabete, und das Padding ist ihnen egal.
Buffer.from("PDw_Pz8-Pg==", "base64").toString(); // <<???>>
Buffer.from("PDw/Pz8+Pg==", "base64url").toString(); // <<???>>
Das ist praktisch für JWTs und Tokens (probieren Sie den JWT-Decoder), beachten Sie aber den Abschnitt zur Validierung weiter unten. Hintergrund zu den beiden Alphabeten: Base64 vs. Base64URL.
Eine Datei kodieren und dekodieren
fs akzeptiert "base64" als Kodierung, was in beide Richtungen einen Schritt spart:
import { readFileSync, writeFileSync } from "node:fs";
readFileSync("hello.txt").toString("base64"); // aGVsbG8K
readFileSync("hello.txt", "base64"); // aGVsbG8K (same thing)
writeFileSync("copy.txt", Buffer.from("aGVsbG8K", "base64"));
writeFileSync("copy2.txt", "aGVsbG8K", "base64"); // decodes while writing
Um eine Datei in HTML oder CSS einzubetten, setzen Sie ein Präfix vor das Ergebnis: `data:image/png;base64,${b64}`. Der Data-URI-Generator baut denselben String im Browser.
Große Dateien streamen
Eine 2-GB-Datei zum Kodieren in den Speicher zu laden ist keine gute Idee. Ein Transform-Stream kann Block für Block kodieren, solange er nur vollständige Gruppen aus 3 Bytes kodiert und den Rest in den nächsten Block übernimmt:
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import { Transform } from "node:stream";
class Base64Encode extends Transform {
constructor() { super(); this.rest = Buffer.alloc(0); }
_transform(chunk, _enc, cb) {
const buf = Buffer.concat([this.rest, chunk]);
const cut = buf.length - (buf.length % 3);
this.rest = buf.subarray(cut);
cb(null, buf.subarray(0, cut).toString("base64"));
}
_flush(cb) { cb(null, this.rest.toString("base64")); }
}
await pipeline(createReadStream("big.bin"), new Base64Encode(),
createWriteStream("big.b64"));
Bei einer zufälligen 1-MB-Datei stimmte die Ausgabe exakt mit readFileSync("big.bin").toString("base64") überein. Ohne den Übertrag würde jede Blockgrenze, die kein Vielfaches von 3 ist, =-Padding mitten in die Ausgabe setzen. Den Grund erklärt So funktioniert Base64.
Die dekodierte Größe ohne Dekodieren erfahren Sie mit Buffer.byteLength("aGVsbG8K", "base64"), das 6 zurückgibt.
Eingaben prüfen
Buffer.from(s, "base64") wirft bei fehlerhaftem Inhalt nie einen Fehler. Es verwirft Zeichen, die in keinem der beiden Alphabete vorkommen, und liefert, was übrig bleibt:
Buffer.from("aGk=!!", "base64"); // <Buffer 68 69>
Buffer.from("not base64 at all", "base64"); // <Buffer 9e 8b 5b 6a c7 ba e1 ab 5a 96>
Buffer.from("aGk", "base64").toString(); // hi (missing padding is fine)
Bei nicht vertrauenswürdigen Eingaben prüfen Sie Alphabet und Länge, kodieren dann erneut und vergleichen. Der Roundtrip erkennt Padding-Bits ungleich null wie bei aGl=, das ebenfalls zu hi dekodiert wird, aber nicht kanonisch ist.
function isBase64(s) {
return /^[A-Za-z0-9+/]*={0,2}$/.test(s) && s.length % 4 === 0 &&
Buffer.from(s, "base64").toString("base64") === s;
}
isBase64("aGk="); // true
isBase64("aGk"); // false (no padding)
isBase64("aGl="); // false (non-canonical)
isBase64("not base64"); // false
Für base64url passen Sie den regulären Ausdruck auf [A-Za-z0-9_-] an und lassen die Längenprüfung weg. Der Base64-Validator zeigt dieselben Prüfungen interaktiv.
Fallstricke und Fehlermeldungen
- Falscher Argumenttyp.
Buffer.from(123, "base64")wirftTypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received type number (123). Meist ist einundefinedoder eine Zahl aus JSON hineingerutscht. new Buffer(). Der Konstruktor ist aus Sicherheitsgründen veraltet (DEP0005). Verwenden SieBuffer.fromoderBuffer.alloc.- Binärdaten als Text dekodieren.
.toString("utf8")auf Bild-Bytes erzeugt ohne Fehler Ersatzzeichen (U+FFFD), und die Datei ist beim Zurückschreiben beschädigt. Behalten Sie Binärdaten alsBuffer. - Data-URI-Präfix.
Buffer.from("data:image/png;base64,iVBOR...", "base64")scheitert nicht, sondern dekodiert das Präfix als Datenmüll. Trennen Sie vorher am Komma. - Zeilenumbrüche. Node ignoriert
\nund\rbeim Dekodieren, MIME-umbrochene Eingaben funktionieren also, aber der Encoder bricht nie um. Verwenden Sieb64.match(/.{1,76}/g).join("\r\n"), wenn Sie MIME-Zeilen brauchen.
Versionshinweise
- Kodierung
base64url: Node.js 15.7.0 und 14.18.0. - Globale Funktionen
btoaundatob: Node.js 16.0, als Legacy markiert. Uint8Array.prototype.toBase64undUint8Array.fromBase64sind in Node.js 24 nicht verfügbar (typeofliefert"undefined"). Sie kommen mit neueren V8-Versionen; bis dahin führt der Weg überBuffer.Buffer.from(string, "base64")hat in jeder Version Leerraum und ungültige Zeichen ignoriert, verlassen Sie sich zur Validierung also nicht darauf.
Häufige Fragen
Wirft Buffer.from(str, 'base64') bei ungültiger Eingabe einen Fehler?
Nein. Node überspringt Zeichen außerhalb des Alphabets und hört beim ersten = auf, Datenmüll wird also ohne jeden Fehler zu irgendwelchen Bytes dekodiert. Prüfen Sie den String selbst, wenn die Eingabe nicht vertrauenswürdig ist.
Mit welcher Node.js-Version kam base64url?
Die Kodierung base64url kam mit Node.js 15.7.0 und wurde auf 14.18.0 zurückportiert. Auf jeder aktuellen Version können Sie sich darauf verlassen.
Soll ich in Node.js btoa verwenden?
Node stuft btoa und atob als Legacy ein und empfiehlt Buffer. Sie existieren für die Kompatibilität mit Browsern und haben dieselbe Latin-1-Einschränkung, die unter Base64 in JavaScript beschrieben ist.