Codifica Base64 in Dart: una guida completa
Hai dei byte, e ti serve una stringa. Il payload può essere un file, una credenziale di autenticazione, un token di configurazione, o un blob binario che viaggia dentro un documento JSON, e il canale accetta solo testo. Il Base64 è lo scambio che risolve il problema: ogni tre byte in ingresso diventano quattro caratteri tratti da un alfabeto di 64 caratteri, quindi l'output è sempre un multiplo pulito di quattro e sempre sicuro nei mondi solo testo. Il prezzo è fisso: 33 percento in più di caratteri, e il formato aggiunge uno o due caratteri di padding = alla fine quando l'ultimo frammento è corto. Questa guida è la ricetta Dart per fare questo scambio correttamente.
Niente da installare. Base64 è a bordo in dart:convert dal Dart 1.13 del 2015, e l'API è stabile da allora; entrambi gli alfabeti, standard e URL-safe, sono disponibili da oltre un decennio. La home page spiega il formato nel dettaglio; qui c'è la parte codifica del lavoro: l'intera superficie API, la disciplina "prima i byte" che evita il bug più comune, le scelte di padding e alfabeto, e i compiti nel mondo reale: JWT, data URI, upload di file, header HTTP, MIME, configurazione, stream e riga di comando. La decodifica, la direzione opposta, ha la sua guida, collegata in fondo.
Un import, due alfabeti, una regola di padding
L'intera superficie pubblica per la codifica vive in dart:convert:
| Voce | Alfabeto | Quando usarlo |
|---|---|---|
base64Encode(bytes) |
standard: A-Z a-z 0-9 + /, con padding |
API, MIME, autenticazione Basic, la maggior parte dei consumatori |
base64UrlEncode(bytes) |
URL-safe: A-Z a-z 0-9 - _, sempre con padding |
URL, nomi di file, JWT, ID di oggetto |
base64.encode(bytes) |
standard, identico alla chiamata di livello superiore | Trasformazioni di stream e pipeline di codec |
Base64Encoder().convert(bytes) |
standard | Se vuoi un'istanza di codificatore nominata |
Due regole coprono tutte e quattro le righe. Prima, l'input deve essere una lista di valori byte, interi da 0 a 255; qualsiasi altra cosa, inclusi i negativi o i valori da 256 in su, lancia un ArgumentError che indica l'indice sbagliato. Secondo, l'output è sempre con padding: non c'è nessun flag, costruttore o opzione che produca output senza padding, perché il padding del formato è una proprietà dei dati, e le specifiche che vogliono toglierlo lo tolgono come passo separato e documentato. L'esempio più piccolo possibile, da capo a fondo:
import 'dart:convert';
void main() {
final text = 'Dart is open source';
final bytes = utf8.encode(text);
final encoded = base64Encode(bytes);
print(encoded); // RGFydCBpcyBvcGVuIHNvdXJjZQ==
}
Prima i byte: l'ordine che ti salva
Il bug base64 più comune in Dart non c'entra nulla con il base64. C'entra con l'ordine delle operazioni. Una String di Dart è una sequenza di unità di codice UTF-16, e chiamare base64Encode(text.codeUnits) impacchetta quelle unità a 16 bit, non i byte che il destinatario si aspetta. Per l'ASCII puro i due casi coincidono per fortuna, ed è per questo che il bug resta nascosto finché non arriva il primo carattere accentato, un'emoji o un testo CJK. Allora il codificatore rifiuta il lavoro, perché un'unità di codice come 0x4e16 non è un valore byte:
import 'dart:convert';
void main() {
final message = 'Héllo Wörld 世界';
print(utf8.encode(message).length); // 20
print(message.codeUnits.length); // 14
print(base64Encode(utf8.encode(message)));
try {
base64Encode(message.codeUnits);
} on ArgumentError catch (e) {
print(e);
}
}
Il ArgumentError punta all'indice esatto in difetto, quindi il fallimento è rumoroso, non silenzioso. La disciplina da tenere: decidi cosa sono i byte prima di parlare con il base64. Il testo passa da una codifica nominata, utf8.encode per i dati moderni, e la List<int> risultante è ciò che viene impacchettato. I byte da un file o da uno socket di rete arrivano già come Uint8List, che è la forma giusta per il codificatore senza nessuna conversione.
Padding: il compito del codificatore
Il Base64 mappa gruppi di tre byte in quattro caratteri, quindi un payload la cui lunghezza non è un multiplo di tre lascia un gruppo parziale in fondo. Il formato segna quel deficit con i caratteri =: un byte in ingresso diventa quattro caratteri più due pad, due byte diventano quattro caratteri più un pad, tre byte diventano esattamente quattro caratteri. Il codificatore di Dart lo fa per te, senza condizioni:
import 'dart:convert';
void main() {
print(base64Encode([0x41])); // QQ==
print(base64Encode([0x41, 0x42])); // QUI=
print(base64Encode([0x41, 0x42, 0x43])); // QUJD
}
Quel comportamento senza condizioni è una funzionalità: l'output è sempre una stringa base64 legale e auto-descrittiva. Quando una specifica chiede la variante senza padding, e i JWT sono la ragione più comune, la rimozione è il tuo passo esplicito e visibile, non un'impostazione della libreria:
base64UrlEncode(bytes).replaceAll('=', '')
Metti la rimozione dove c'è il confine della specifica, dagli un nome e documentala. Il lato decodifica di questo scambio, incluso come viene riparato l'input danneggiato o spogliato, è coperto nella guida alla decodifica.
Base64 URL-safe
L'alfabeto standard contiene +, / e =, e quei tre caratteri sono in conflitto con la sintassi URL: separatori di query, separatori di percorso e delimitatori di parametri. L'alfabeto URL-safe, standardizzato come base64url nell'RFC 4648, sostituisce + con - e / con _, così l'output può stare in un segmento di percorso, in un valore di query o in un nome file senza escape. Ecco la differenza su dei byte che mettono alla prova entrambi i caratteri sostituiti:
import 'dart:convert';
void main() {
final tricky = [0xfb, 0xff, 0xfe, 0xf9];
print(base64Encode(tricky)); // +//++Q==
print(base64UrlEncode(tricky)); // -__--Q==
}
Scegli in base al consumatore, non al gusto. Se il valore vivrà in un URL, in un JWT o in un nome file, codifica con base64UrlEncode e toglie il padding se la specifica è senza padding. Se il valore sarà un corpo MIME, un header di autenticazione Basic o un campo in un contratto API che dice "base64", usa l'alfabeto standard, perché base64 senza qualifiche significa quello standard. I due alfabeti non sono intercambiabili agli occhi dei consumatori rigorosi: un server che si aspetta base64 standard può rifiutare un payload contenente - con un 400 e niente di più utile.
Charset: quali byte stai impacchettando?
Quando l'input è testo, il passaggio di codifica decide quali byte vedrà il base64, e il consumatore si aspetta un charset dall'altra parte. Se la tua ipotesi e quella del consumatore non coincidono, l'output è base64 perfettamente valido dei byte sbagliati, il peggior tipo di bug, perché nulla lancia un errore. Per qualsiasi scambio moderno, UTF-8 è il default; le altre codifiche a byte singolo esistono per i dati legacy:
| Codifica | Quando usarla | Codifica con |
|---|---|---|
utf8 |
Testo moderno, JSON, qualsiasi cosa sul web | utf8.encode(text) |
latin1 |
Dati legacy occidentali a byte singolo | latin1.encode(text) |
ascii |
Testo 7 bit semplice | ascii.encode(text) |
import 'dart:convert';
void main() {
final modern = base64Encode(utf8.encode('Héllo'));
final legacy = base64Encode(latin1.encode('Héllo'));
print(modern); // SMOpbGxv
print(legacy); // SOlsbG8=
}
Stessa parola, byte diversi, base64 diverso. Nota le lunghezze: l'UTF-8 serve sei byte per Héllo, perché l'accento è una sequenza di due byte, mentre il Latin-1 la infila in cinque. Se il consumatore decodifica con la codifica che non hai usato, otterrà del mojibake, e sembrerà che i dati si siano corrotti in transito quando in realtà si sono corrotti già nell'intenzione.
JWT: scrivere il token
Un JSON Web Token è fatto di tre parti base64url unite da punti: header, payload, firma. L'RFC 7515 fissa due dettagli: l'alfabeto è URL-safe e il padding viene omesso, perché il token è pensato per stare in URL e header. La firma per l'algoritmo HS256 è l'HMAC-SHA256 di header.payload, esso stesso base64url senza padding. Costruirla a mano con il pacchetto crypto richiede poche righe, ed è più trasparente di quanto sembri:
import 'dart:convert';
import 'package:crypto/crypto.dart';
String base64UrlNoPadding(List<int> bytes) {
return base64UrlEncode(bytes).replaceAll('=', '');
}
String createJwt(Map<String, dynamic> header, Map<String, dynamic> payload,
List<int> secretKey) {
final signingInput =
'${base64UrlNoPadding(utf8.encode(jsonEncode(header)))}.'
'${base64UrlNoPadding(utf8.encode(jsonEncode(payload)))}';
final mac = Hmac(sha256, secretKey).convert(utf8.encode(signingInput));
final signature = base64UrlNoPadding(mac.bytes);
return '$signingInput.$signature';
}
void main() {
final token = createJwt(
{'alg': 'HS256', 'typ': 'JWT'},
{'sub': 'user-42', 'exp': 1893456000},
utf8.encode('a-32-byte-secret-key-0123456789'),
);
print(token);
}
La firma viene calcolata sui byte esatti che sono stati impacchettati, quindi finché firmi la stessa stringa che emetti, la verifica dall'altra parte è una ripetizione degli stessi passi. Tre avvertimenti. Il vecchio pacchetto jwt su pub.dev è del 2014 e precede la null safety; la risposta funzionante dell'ecosistema è fare quello che mostriamo qui con crypto. Non emettere mai un token con alg: none, e non lasciare mai che sia un client a scegliere l'algoritmo. E ricorda che il payload è leggibile da chiunque, quindi includi solo ciò che il token deve provare.
Data URI: spedire file dentro il testo
Un data URI, definito dall'RFC 2397, è un URL il cui payload è i dati stessi. Il contenuto binario in un data URI è codificato in base64, ed è per questo che il formato compare ovunque i documenti di testo debbano incorporare immagini, font o allegati: attributi HTML, CSS, JSON, file di configurazione. Il Dart può costruire gli URI nativamente, senza nessun pacchetto URI:
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
final png = await File('icon.png').readAsBytes();
final imageUri = Uri.dataFromBytes(png, mimeType: 'image/png');
print(imageUri); // data:image/png;base64,iVBOR...
final note = Uri.dataFromString('Hello, Dart!');
print(note); // data:,Hello,%20Dart!
}
Uri.dataFromBytes codifica in base64 di default (ha un'opzione percentEncoded: true per l'altra forma), che è la codifica corretta per il binario. Uri.dataFromString fa il percent-encoding di default, perché il testo corto è più corto così, e accetta il flag base64: true quando vuoi la forma con i byte impacchettati. Il traboccolo pratico è la scala: il payload viaggia dentro il documento, con un sovraccarico del 33 percento, quindi i data URI sono per asset piccoli, icone e miniature, non per spedire megabyte attraverso CSS.
File: impacchettare byte per canali di testo
Il compito di tutti i giorni: un file che deve viaggiare attraverso JSON, un file di configurazione o qualsiasi trasporto solo testo. Lo schema è: leggi i byte, codifica, incorpora:
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
final image = await File('photo.jpg').readAsBytes();
final encoded = base64Encode(image);
final upload = jsonEncode({
'name': 'photo.jpg',
'size': image.length,
'data': encoded,
});
print('payload ${upload.length} chars for ${image.length} bytes');
}
Il numero da tenere a mente è la crescita: un file da 2.000 byte diventa 2.668 caratteri base64, e un po' di più quando entrano in gioco le chiavi JSON. Due traboccoli. Prima, controlla che il tuo input non sia già codificato: fare il base64 di una stringa già in base64 è il classico bug della doppia codifica, e si decodifica con "successo" in un'altra parete di base64. Secondo, se il canale può portare dati binari, ed è per questo che esiste multipart/form-data, porta dati binari: è un quarto più piccolo, e la tassa base64 è puro spreco.
HTTP e API: header e payload
Il compito di codifica più familiare in HTTP è l'header Authorization: Basic: la parola Basic, uno spazio, e il base64 con alfabeto standard di username:password:
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<void> main() async {
final credentials = base64Encode(utf8.encode('octocat:secret'));
final client = http.Client();
final response = await client.get(
Uri.parse('https://httpbin.org/basic-auth/octocat/secret'),
headers: {'Authorization': 'Basic $credentials'},
);
print(response.statusCode);
client.close();
}
Con il pacchetto http, a un dart pub add http di distanza, l'header è solo una stringa nella richiesta. Il traboccolo è la cornice di sicurezza: qui il base64 è offuscamento, non protezione. Chiunque può invertirlo in un passo, ed è esattamente per questo che l'autenticazione Basic ha senso solo su connessioni TLS, dove a proteggere è il trasporto, non la codifica. Per i campi payload delle API, segui il contratto: se dice base64, è l'alfabeto standard con padding, e la variante URL-safe è un'altra cosa che i consumatori rigorosi rifiuteranno.
Email e MIME: avvolgimento a 76
Il MIME, il sistema che permette alle email di portare dati binari, usa il base64 come codifica di trasferimento del contenuto, e l'RFC 2045 specifica che le righe codificate non devono superare i 76 caratteri, con CRLF tra loro. Il limite è una convenzione MIME - 76 più CRLF stanno comodi su un display a 80 colonne - e ogni codificatore conforme avvolge. Il codificatore di Dart produce un'unica stringa ininterrotta, quindi l'avvolgimento è un breve passo di post-elaborazione:
import 'dart:convert';
String wrapForMime(String base64Text, [int lineLength = 76]) {
final buffer = StringBuffer();
for (var i = 0; i < base64Text.length; i += lineLength) {
final end = i + lineLength > base64Text.length
? base64Text.length
: i + lineLength;
buffer
..write(base64Text.substring(i, end))
..write('\r\n');
}
return buffer.toString();
}
void main() {
final encoded = base64Encode(utf8.encode('Hello from an email attachment'));
print(wrapForMime(encoded));
}
Avvolgi la stringa finita, padding incluso, e lascia che l'ultima riga sia lunga quanto è, fino a 76. L'unica cosa da non fare è togliere il padding prima di avvolgere nella speranza di salvare un carattere: i pad fanno parte del contenuto codificato, e un consumatore che riassembla le righe rifiuterà il risultato senza di essi.
Configurazione: i segreti in una riga
Token, chiavi e credenziali che contengono virgolette, a capo o altri caratteri scomodi a volte sono codificati in base64 per stare puliti in una riga di configurazione o in una variabile CI. La cornice onesta prima di tutto: questo è offuscamento, non cifratura, e qualsiasi cosa che arrivi in un repository o in un log è pubblica. Usa lo schema per ordine, mai per segretezza. Codificare il valore è una chiamata:
import 'dart:convert';
String forEnvFile(String secret) {
return base64Encode(utf8.encode(secret));
}
void main() {
final line = 'API_TOKEN_B64=${forEnvFile('sk-live-abc123')}';
print(line); // API_TOKEN_B64=c2stbGl2ZS1hYmMxMjM=
}
Il valore poi sta in un file .env, in un segreto CI o in una definizione a tempo di compilazione, e torna come testo normale dopo una sola decodifica. Se il segreto deve essere protetto in transito o a riposo, rivolgiti a un secret manager o a una libreria di cifratura; il compito del base64 qui è mantenere semplice la gestione del testo della pipeline, nient'altro.
Stream: codifica oltre i confini dei frammenti
Quando i byte arrivano a frammenti, una lettura di rete, un file elaborato a blocchi, il codificatore si occupa dei frammenti senza che tu debba allineare niente. Il codec porta il gruppo parziale oltre i confini dei frammenti, quindi le dimensioni dei frammenti non devono essere multiple di tre:
import 'dart:convert';
import 'dart:typed_data';
Future<void> main() async {
final data = Uint8List(100000);
for (var i = 0; i < data.length; i += 31) {
data[i] = i % 256;
}
final chunks = <List<int>>[data.sublist(0, 777), data.sublist(777)];
final encoded = await Stream.fromIterable(chunks)
.transform(base64.encoder)
.join();
print('in: ${data.length}, out: ${encoded.length}'); // in: 100000, out: 133336
}
Due frammenti dalle dimensioni scomode, 777 e 99.223 byte, producono una stringa corretta di 133.336 caratteri, perché il codificatore parcheggia i bit residui di ogni gruppo incompleto finché non arriva il frammento successivo, ed emette il padding solo alla fine. Se preferisci i sink, base64.encoder.startChunkedConversion ti dà la stessa macchina a stati come ByteConversionSink (gli dai frammenti di byte, lui emette stringhe), ed è l'adattamento naturale per scrivere output grandi su un file o uno socket senza mai unire tutto in un'unica grande stringa.
Dati grandi: velocità di elaborazione e memoria
I calcoli sulle dimensioni sono esatti e vale la pena tenerli a mente: la lunghezza dell'output è la lunghezza dell'input divisa per tre, arrotondata per eccesso, per quattro. Uno, due o tre byte costano tutti quattro caratteri; da lì in poi è un sovraccarico piatto del 33 percento. La formula, per quando devi riservare buffer o segnalare i progressi:
import 'dart:convert';
int encodedLength(int n) => (n + 2) ~/ 3 * 4;
void main() {
print(encodedLength(100000)); // 133336
}
La velocità non è il vincolo; il codificatore è un singolo passaggio di ricerca in tabella che gestisce megabyte in millisecondi. I vincoli sono la tassa sulle dimensioni in sé, addebitata sulla rete e in memoria, e il fatto che la forma codificata sia una stringa. Tieni a mente entrambe le cose su larga scala: per i payload che possono crescere grandi, fai la codifica in streaming come mostrato sopra invece di accumulare una grande lista e una grande stringa, e per trasferimenti ripetuti degli stessi dati, chiedi se il canale ha una modalità binaria, perché il 33 percento è un sovrapprezzo permanente che nessun algoritmo può rimborsare.
Il codificatore da riga di comando
La VM mette a disposizione un CLI pulito per il codificatore. Questo strumento legge un argomento file o lo standard input e stampa la codifica con l'alfabeto standard:
import 'dart:convert';
import 'dart:io';
Future<void> main(List<String> args) async {
final bytes = await _read(args);
stdout.writeln(base64Encode(bytes));
}
Future<List<int>> _read(List<String> args) async {
if (args.isNotEmpty) {
return File(args[0]).readAsBytes();
}
final all = <int>[];
await for (final chunk in stdin) {
all.addAll(chunk);
}
return all;
}
Salvalo come bin/encode.dart ed eseguilo con dart run bin/encode.dart photo.jpg > photo.b64, oppure usa un pipe con cat config | dart run bin/encode.dart. Il compagno, un decodificatore che legge e appiattisce, è il primo esempio nella guida alla decodifica, e insieme i due script sono un kit piccolo ma davvero utile per muovere dati binari attraverso canali di testo.
I traboccoli che mordono in uscita
- La trappola di codeUnits.
base64Encode(text.codeUnits)impacchetta unità UTF-16, non byte; funziona per l'ASCII e lanciaArgumentErroralla prima unità di codice sopra 255. Codifica sempre il testo prima con una codifica nominata. - Alfabeto sbagliato. Dare in pasto un output URL-safe a un consumatore che si aspetta l'alfabeto standard è un 400 in arrivo. Decidi l'alfabeto dalla specifica, codifica una volta sola, e non convertire a posteriori.
- Ipotesi sul padding. Il Dart fa sempre il padding. Se la specifica vuole senza padding, toglilo con
replaceAll('=', '')come passo esplicito al confine, e dillo nel contratto. - Deriva del charset. Codificare byte Latin-1 per un consumatore che decodifica UTF-8 produce base64 valido dei dati sbagliati. Nulla lancia un errore; il testo è semplicemente sbagliato.
- Doppia codifica. Fare il base64 di un valore che è già base64, un token copiato da un'altra configurazione, è il classico bug del "si decodifica in un'altra parete di base64".
- L'illusione della privacy. Il base64 è un formato, non un cifrario. Se il modello di minacce prevede un lettore, la risposta è la cifratura, non la codifica.
- Pacchetti datati. Il pacchetto
jwtdi lunga data su pub.dev precede la null safety; per il lavoro sui JWT,cryptopiù le poche righe qui sopra è il percorso mantenuto.
Quando servirsi di qualcos'altro
- Upload di file su HTTP. Usa
multipart/form-data; porta byte grezzi, così salti la tassa del 33 percento del tutto. - Payload grandi o ripetitivi. Comprimi prima, codifica dopo: il base64 di testo gzip è drammaticamente più piccolo del base64 del testo, e il lato che decomprime già conosce il formato.
- Testo corto dentro URL. Il percent-encoding è più corto per un pugno di caratteri e mantiene il valore leggibile dall'uomo; i data URI lo fanno persino per te di default.
- Output di debug e log. L'esadecimale è il 50 percento più lungo del base64 (il doppio della dimensione grezza, il base64 solo quattro terzi), ma è molto più facile da scansionare, confrontare con diff e passare a un collega; per gli stralci binari nei log di solito vince.
Le buone pratiche, la lista del codificatore
- Codifica byte, mai unità di codice; il testo passa prima da una codifica nominata.
- Scegli l'alfabeto dalla specifica del consumatore prima di scrivere la chiamata.
- Togli il padding solo dove la specifica dice senza padding, come passo visibile al confine.
- Dichiara il charset esplicitamente nel contratto; non dare nulla per scontato sull'altro lato.
- Fai in streaming tutto ciò che può crescere grande.
- Tratta il base64 come un formato per canali solo testo, mai come una protezione per dati sensibili.
Una breve storia di due alfabeti
Il formato che hai appena usato è più vecchio di ogni rilascio di Dart, e le scelte di alfabeto che hai a disposizione sono state standardizzate decenni prima dell'arrivo di Dart. La versione corta:
- 1993, RFC 1521: il MIME introduce il base64 come codifica di trasferimento del contenuto per le email, con l'alfabeto standard di 64 caratteri e il limite di 76 caratteri per riga a cui questo articolo avvolge. Il compito del formato, portare dati binari attraverso canali di testo, risale da qui.
- 1996, RFC 2045: l'obsolescenza del MIME che ha reso le regole di padding e di lunghezza di riga del base64 lo standard durevole.
- 2006, RFC 4648: la codifica viene estratta dal MIME e standardizzata di per sé, aggiungendo l'alfabeto URL-safe e il consiglio che i decodificatori dovrebbero rifiutare l'input non valido. La scelta a due alfabeti che ottieni in Dart viene da questo documento.
- 2015, RFC 7515: i JSON Web Signatures specificano base64url senza padding, la convenzione dietro ogni JWT.
- Novembre 2015, Dart 1.13: il base64 arriva in
dart:convert; la variante URL-safe segue nel Dart 1.16 la primavera successiva, e le chiamate di livello superiorebase64Encodeebase64UrlEncodeche hai usato qui sopra arrivano nel Dart 2.0 del 2018. - Oggi, Dart 3.13: entrambi gli alfabeti, sempre con padding, a un import di distanza, la stessa macchina rigorosa e semplice dal 2015.
Il sovraccarico del 33 percento non è cambiato nemmeno dal 1993. È una proprietà della matematica, quattro simboli per tre byte, e ogni implementazione che userai, in ogni linguaggio, la paga identicamente.
Fatti divertenti dal banco di codifica
- Il codificatore non si può spegnere: non c'è nessun flag per l'output senza padding nell'SDK, ed è per questo che "togli i pad" è sempre il tuo codice, al tuo confine, alla luce del sole.
- Un byte diventa quattro caratteri:
base64Encode([65])èQQ==. La stringa base64 più corta possibile è lunga quattro caratteri, e solo i primi due portano informazione; gli ultimi due sono padding. - Entrambi i codificatori di Dart fanno il padding, anche
base64UrlEncode. Il "senza padding" nel base64url è una convenzione dei consumatori dall'RFC 7515, non una proprietà dell'alfabeto. - L'alfabeto standard è stato progettato per essere stampabile in 7 bit, ed è rimasto il default da allora; il fatto che
+e/abbiano alla fine guadagnato sostituti URL-safe è un segno di quanto sia diventato centrale, non un difetto. - Gli stessi 20 byte UTF-8 di
Héllo Wörld 世界si impacchettano inSMOpbGxvIFfDtnJsZCDkuJbnlYw=, mentre le 14 unità di codice della stringa farebbero fallire il codificatore all'indice 12. Stessi caratteri, due output completamente diversi, uno dei quali un errore. - I file PEM, i blocchi
-----BEGIN CERTIFICATE-----in ogni certificato TLS, sono base64 avvolto a 64 caratteri con header, e il formato risale al 1987, sei anni prima che il MIME pubblicasse il base64 per le email.
Ora hai tutta la parte codifica: la superficie API, la disciplina "prima i byte", le decisioni su padding e alfabeto, e gli schemi funzionanti per JWT, data URI, file, HTTP, MIME, configurazione, stream e terminale. La direzione inversa, prendere a parte una di queste stringhe, con tutta la rigidità del decodificatore, la sua sorpresa delle percent-escape e i suoi strumenti di riparazione, è coperta nella guida alla decodifica Base64, collegata qui sotto.
Ultimo aggiornamento: 2026-09-08
Articolo correlato: Decodifica Base64 in Dart: una guida completa