Base64 i webbläsaren och Node.js: ett bytekontrakt, två API:er

Använd TextEncoder i webbläsare och Buffer i Node.js och testa sedan deras utdata mot samma Unicode och binära fixturer.

En webbläsarklient och en Node.js-tjänst bör producera samma Base64 för samma byte. De behöver inte använda samma API för att göra det. Det viktiga avtalet är byte-representationen av text, alfabetet och behandlingen av utfyllnad och ogiltig inmatning.

Webbläsare: gör steget UTF-8 explicit

De traditionella webbläsarfunktionerna fungerar på bytesträngar. Konvertera Unicode-text med TextEncoder, koda sedan dessa byte. På returvägen, rekonstruera en byte-array och avkoda UTF-8 explicit. Det här exemplet använder en loop för att undvika att expandera en stor array till funktionsargument, även om en produktionsfilkodare fortfarande bör använda bounded chunks eller en lämplig byte API.

const text = '中文😊';
const bytes = new TextEncoder().encode(text);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
const encoded = btoa(binary);
console.log(encoded); // 5Lit5paH8J+Yig==
const decodedBytes = Uint8Array.from(atob(encoded), c => c.charCodeAt(0));
const decoded = new TextDecoder('utf-8', { fatal: true }).decode(decodedBytes);
console.log(decoded); // 中文😊

Node.js: håll Buffer vid bytegränsen

Buffer.from(text, 'utf8') gör textkodningen synlig. Ringer toString('base64') representerar sedan dessa bytes. Avkodning till en Buffer bevarar binär data; att omedelbart konvertera till en UTF-8-sträng är endast lämplig när nyttolasten är känd för att vara text.

import { Buffer } from 'node:buffer';
const encoded = Buffer.from('中文😊', 'utf8').toString('base64');
console.log(encoded); // 5Lit5paH8J+Yig==
const bytes = Buffer.from(encoded, 'base64');
console.log(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); // 中文😊

Den ödesdigra TextDecoder i exemplet är avsiktlig. Vanlig Buffer UTF-8 strängkonvertering kan infoga ersättningstecken för ogiltig inmatning. En framgångsrik textvisning skulle då dölja att de ursprungliga byten inte kunde representeras troget.

Kom överens om validering separat

Nodens Base64-avkodare accepterar vissa inmatningsformulär som en strängare ansökan kan avvisa. Använd inte en framgångsrik Buffer-konvertering som bevis på att ett protokolls kanoniska representation tillhandahölls. Om exakt syntax är viktig för signaturer, cache-nycklar eller interoperabel serialisering, kontrollera det före avkodning.

För ett delat regressionstest, inkludera ASCII, kinesiska, emoji, en noll byte, byte FF och alla längder runt en tre-byte gräns. Jämför byte över körtider. Testa också URL-säker utdata med en fixtur som faktiskt innehåller de ersatta tecknen; en ingång vars utdata endast är bokstäver kan inte bevisa att variantalternativet fungerar.

När du läser filer i Node, behåll den returnerade Buffer istället för att tillämpa en textkodning på den lästa filen. I webbläsaren, använd File.arrayBuffer(). Dessa små gränsval undviker de flesta oavsiktliga korruptioner. Se Node.js Buffer för Node beteende och MDN: btoa() för webbläsarens byte-string-kontrakt.