Werk je met Base64-indeling? Dan is deze site perfect voor jou! Gebruik onze handige online tool om je gegevens te coderen of te decoderen.

Base64-codering in Dart: een complete gids

Je hebt bytes en je hebt een tekenreeks nodig. De payload kan een bestand zijn, een authenticatie-credential, een configuratie-token, of een binaire blob die in een JSON-document meereist, en het kanaal accepteert alleen tekst. Base64 is de ruil die dat oplost: elke drie invoerbytes worden vier tekens uit een alfabet van 64 tekens, dus de output is altijd een mooi veelvoud van vier en altijd veilig in werelden die alleen tekst accepteren. De prijs is vast: 33 procent meer tekens, en het formaat voegt aan het einde een of twee =-paddingtekens toe als het laatste blok te kort is. Deze gids is het Dart-recept om die ruil correct te maken.

Niets te installeren. Base64 is sinds Dart 1.13 in 2015 opgenomen in dart:convert, en de API is sindsdien stabiel; beide alfabetten, standaard en URL-veilig, zijn al meer dan een decennium beschikbaar. De startpagina doorloopt het format in detail; hier is de coderingskant van het werk: het volledige API-oppervlak, de bytes-eerst-discipline die de meest voorkomende bug voorkomt, de padding- en alfabetkeuzes, en de echte klussen uit de praktijk: JWTs, data-URIs, bestandsuploads, HTTP-headers, MIME, configuratie, streams en de opdrachtregel. Decoderen, de omgekeerde richting, heeft zijn eigen gids, verlinkt aan het einde.

Eén import, twee alfabetten, één paddingregel

Het hele openbare oppervlak voor codering zit in dart:convert:

Ingang Alfabet Grijp ernaar wanneer
base64Encode(bytes) standaard: A-Z a-z 0-9 + /, met padding API's, MIME, Basic-auth, de meeste consumenten
base64UrlEncode(bytes) URL-veilig: A-Z a-z 0-9 - _, nog steeds met padding URLs, bestandsnamen, JWTs, object-IDs
base64.encode(bytes) standaard, identiek aan de topniveau-aanroep Streamtransformaties en codec-pipelines
Base64Encoder().convert(bytes) standaard Je wilt een benoemde encoder-instantie

Twee regels dekken alle vier de rijen. Ten eerste moet de invoer een lijst van byte-waarden zijn, gehele getallen van 0 tot 255; alles anders, inclusief negatieve waarden of 256 en meer, gooit een ArgumentError die de slechte index noemt. Ten tweede is de output altijd met padding: er is geen vlag, constructor of optie die output zonder padding produceert, want de padding van het formaat is een eigenschap van de data, en specificaties die er zonder padding op willen, strippen die als aparte, gedocumenteerde stap. Het kleinste mogelijke voorbeeld, van begin tot eind:

import 'dart:convert';
void main() {
  final text = 'Dart is open source';
  final bytes = utf8.encode(text);
  final encoded = base64Encode(bytes);
  print(encoded); // RGFydCBpcyBvcGVuIHNvdXJjZQ==
}

Bytes eerst: de volgorde die je reddt

De meest voorkomende Dart-base64-bug gaat helemaal niet over base64. Het gaat over de volgorde van bewerkingen. Een Dart-String is een sequentie van UTF-16-code-eenheden, en de aanroep van base64Encode(text.codeUnits) verpakt die 16-bits-eenheden, niet de bytes die de ontvanger verwacht. Voor puur ASCII vallen de twee toevallig samen, en daarom blijft de bug verborgen tot de eerste accentletter, emoji of CJK-tekst opduikt. Dan weigert de encoder het werk, want een code-eenheid zoals 0x4e16 is geen byte-waarde:

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);
  }
}

De ArgumentError wijst naar de exacte schuldige index, dus het falen is luid in plaats van stil. De discipline om aan te houden: beslis eerst wat de bytes zijn, vóór je met base64 praat. Tekst gaat door een benoemde codering, utf8.encode voor moderne data, en de resulterende List<int> is wat er verpakt wordt. Bytes uit een bestand of een netwerksocket arriveren al als Uint8List, en dat is de juiste vorm voor de encoder zonder enige conversie.

Padding: het werk van de encoder

Base64 zet groepen van drie bytes om naar vier tekens, dus een payload waarvan de lengte geen veelvoud van drie is, laat een gedeeltelijke groep achter aan het einde. Het formaat markeert dat tekort met =-tekens: één invoerbyte wordt vier tekens plus twee pads, twee bytes worden vier tekens plus één pad, drie bytes worden precies vier tekens. De Dart-encoder doet dit voor je, onvoorwaardelijk:

import 'dart:convert';
void main() {
  print(base64Encode([0x41])); // QQ==
  print(base64Encode([0x41, 0x42])); // QUI=
  print(base64Encode([0x41, 0x42, 0x43])); // QUJD
}

Dat onvoorwaardelijke gedrag is een feature: de output is altijd een legaal, zichzelf-beschrijvende base64-tekenreeks. Als een specificatie de variant zonder padding vraagt, en JWTs zijn de gebruikelijke reden, is het strippen jouw expliciete, zichtbare stap, geen instelling van de bibliotheek:

base64UrlEncode(bytes).replaceAll('=', '')

Plaats het strippen op de plek van de specificatiegrens, geef het een naam en documenteer het. De decodeerkant van deze ruil, inclusief hoe beschadigde of afgekapte invoer wordt gerepareerd, staat in de decodeergids.

URL-veilige Base64

Het standaardalfabet bevat +, / en =, en die drie tekens botsen met URL-syntax: de query-scheider, de pad-scheider en de parameterscheider. Het URL-veilige alfabet, gestandaardiseerd als base64url in RFC 4648, vervangt + door - en / door _, zodat de output in een padsegment, een query-waarde of een bestandsnaam kan zitten zonder te hoeven escapen. Hier is het verschil aan de hand van bytes die beide verwisselde tekens oproepen:

import 'dart:convert';
void main() {
  final tricky = [0xfb, 0xff, 0xfe, 0xf9];
  print(base64Encode(tricky)); // +//++Q==
  print(base64UrlEncode(tricky)); // -__--Q==
}

Kies op basis van de consument, niet op smaak. Als de waarde in een URL, een JWT of een bestandsnaam komt te zitten, codeer dan met base64UrlEncode en strip de padding als de specificatie zonder padding is. Als de waarde een MIME-body, een Basic-auth-header of een veld in een API-overeenkomst wordt die "base64" zegt, gebruik dan het standaardalfabet, want base64 zonder kwalificatie betekent het standaard alfabet. De twee alfabetten zijn niet met elkaar verwisselbaar in de ogen van strikte consumenten: een server die standaard base64 verwacht, kan een payload met - weigeren met een 400 en niets behulpzams.

Tekensets: welke bytes verpakt je?

Als de invoer tekst is, beslist de coderingsstap welke bytes base64 zal zien, en de consument gaat aan de andere kant uit van een tekenset. Als jouw aanname en die van de consument verschillen, is de output perfect geldige base64 van de verkeerde bytes, het ergste soort bug, want er gooit niets. Voor elke moderne uitwisseling is UTF-8 de standaard; de andere enkele-byte-coderingen bestaan voor legacy-data:

Codering Gebruik het voor Codeer met
utf8 Moderne tekst, JSON, alles op het web utf8.encode(text)
latin1 Oude Westerse enkele-byte-data latin1.encode(text)
ascii Gewone 7-bits-tekst 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=
}

Zelfde woord, andere bytes, andere base64. Let op de lengtes: UTF-8 heeft zes bytes nodig voor Héllo, want het accent is een sequentie van twee bytes, terwijl Latin-1 het in vijf past. Als de consument decodeert met de codering die je niet gebruikte, krijgt hij mojibake, en het lijkt alsof de data onderweg gecorrupt was, terwijl hij in feite gecorrupt was in de bedoeling.

JWTs: het token schrijven

Een JSON Web Token is drie base64url-onderdelen die met punten aan elkaar zitten: header, payload, handtekening. RFC 7515 pakt twee details vast: het alfabet is URL-veilig, en de padding wordt weggelaten, want het token is ontworpen om in URLs en headers te zitten. De handtekening voor het HS256-algoritme is de HMAC-SHA256 van header.payload, zelf base64url zonder padding. De handtekening zelf bouwen met het crypto-pakket is een paar regels, en het is transparanter dan het lijkt:

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);
}

De handtekening wordt berekend over precies de bytes die werden verpakt, dus zolang je ondertekent wat je zelf uitschrijft, is verificatie aan de andere kant een herhaling van dezelfde stappen. Drie waarschuwingen. Het oude jwt-pakket op pub.dev is van 2014 en predatert null safety; het werkende antwoord van het ecosysteem is om te doen wat hier getoond wordt, met crypto. Geef nooit een token uit met alg: none, en laat nooit een client het algoritme kiezen. En onthoud dat de payload door iedereen gelezen kan worden, dus neem alleen mee wat het token moet aantonen.

Data-URIs: bestanden vervoeren in tekst

Een data-URI, gedefinieerd in RFC 2397, is een URL waarvan de payload de data zelf is. Binaire inhoud in een data-URI is base64-gecodeerd, en daarom duikt het format overal op waar tekstdocumenten afbeeldingen, fonts of bijlagen moeten inbedden: HTML-attributen, CSS, JSON, configuratiebestanden. Dart kan de URIs natief bouwen, zonder URI-pakket:

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 is standaard base64-gecodeerd (er is een percentEncoded: true-opt-in voor de andere vorm), en dat is de juiste codering voor binair. Uri.dataFromString is standaard percent-gecodeerd, want korte tekst is op die manier korter, en accepteert een base64: true-vlag wanneer je de bytes-verpakte vorm wilt. De praktische valkuil is schaal: de payload reist mee in het document, met 33 procent overhead, dus data-URIs zijn voor kleine assets, iconen en thumbnails, niet voor megabytes door CSS duwen.

Bestanden: bytes verpakken voor tekstkanalen

De alledaagse klus: een bestand dat door JSON, een configuratiebestand of elke tekst-en-alleen overdracht moet reizen. Het patroon is: bytes lezen, coderen, inbedden:

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');
}

Het getal om in je hoofd te houden is de groei: een bestand van 2.000 bytes wordt 2.668 base64-tekens, en een beetje meer als de JSON-keys erbij komen. Twee valkuilen. Eerst, controleer dat je invoer niet al gecodeerd is: een al-base64-tekenreeks base64-coderen is de klassieke dubbele-codering-bug, en hij decodeert "succesvol" naar nog een muur van base64. Ten tweede, als het kanaal binair kan vervoeren, en dat is waar multipart/form-data voor bestaat, vervoer dan binair: het is een kwart kleiner, en de base64-belasting is puur verspilling.

HTTP en API's: headers en payloads

De bekendste coderingsklus in HTTP is de Authorization: Basic-header: het woord Basic, een spatie, en de base64 van username:password in het standaardalfabet:

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();
}

Met het http-pakket, op één dart pub add http afstand, is de header gewoon een string in de request. De valkuil zit in de beveiligingsframing: base64 is hier obfuscatie, geen bescherming. Iedereen kan het in één stap terugdraaien, en precies daarom hoort Basic auth alleen op TLS-verbindingen, waar de transport, niet de codering, het beschermt. Voor de payload-velden van een API volg je de overeenkomst: als het base64 zegt, dan is dat het standaardalfabet met padding, en is de URL-veilige variant een ander ding dat strikte consumenten zullen weigeren.

E-mail en MIME: omwikkeling op 76

MIME, het systeem dat e-mail binair laat vervoeren, gebruikt base64 als content transfer encoding, en RFC 2045 schrijft voor dat gecodeerde regels niet langer mogen zijn dan 76 tekens, met CRLF ertussen. De limiet is een MIME-conventie - 76 plus CRLF past ruim op een 80-kolommen-weergave - en elke conforme encoder omwikkelt. De encoder van Dart produceert één ononderbroken tekenreeks, dus het omwikkelen is een korte nabewerkingsstap:

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));
}

Wikkel de afgeronde tekenreeks om, padding inbegrepen, en laat de laatste regel zo lang zijn als hij is, tot 76. Het enige dat je niet moet doen is de padding voor het omwikkelen strippen in de hoop een teken te besparen: de pads zijn onderdeel van de gecodeerde inhoud, en een consument die de regels weer samenraagt, wijst het resultaat zonder ze af.

Configuratie: secrets op één regel

Tokens, keys en credentials met aanhalingstekens, regeleindes of andere lastige tekens worden soms base64-gecodeerd zodat ze net op een configuratieregel of een CI-variabele passen. Eerst de eerlijke framing: dit is obfuscatie, geen versleuteling, en alles wat ooit een repository of een log bereikt, is publiek. Gebruik het patroon voor netheid, nooit voor geheimhouding. De waarde coderen is één aanroep:

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=
}

De waarde zit dan in een .env-bestand, een CI-secret of een compile-time define, en komt na één decode terug als gewone tekst. Als het secret beschermd moet worden tijdens transport of opslag, pak dan een secret manager of een versleuteling-bibliotheek; het werk van base64 hier is om de tekstverwerking van de pipeline simpel te houden, niets meer.

Streams: coderen over chunk-grenzen heen

Als de bytes in chunks aankomen, een netwerk-lezing of een bestand dat in blokken wordt verwerkt, komt de encoder ermee klaar zonder dat je iets hoeft uit te lijnen. De codec draagt de gedeeltelijke groep over de chunk-grenzen heen, dus de chunkgroottes hoeven geen veelvoud van drie te zijn:

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
}

Twee ongelukkig grote chunks, 777 en 99.223 bytes, produceren één correcte tekenreeks van 133.336 tekens, want de encoder parkeert de resterende bits van elke onvolledige groep tot de volgende chunk aankomt, en geeft de padding pas aan het einde uit. Als je liever sinks gebruikt, geeft base64.encoder.startChunkedConversion je dezelfde statiemachine als een ByteConversionSink (je voedt hem met byte-chunks en hij geeft tekenreeksen uit), en dat is de natuurlijke pasvorm om grote output naar een bestand of een socket te schrijven zonder ooit één grote tekenreeks bij elkaar te voegen.

Grote data: doorvoer en geheugen

De grootte-wiskunde is exact en de moeite waard om te onthouden: de outputlengte is de invoerlengte gedeeld door drie, afgerond naar boven, vermenigvuldigd met vier. Eén, twee of drie bytes kosten allemaal vier tekens, en vanaf daar is het een vlakke 33 procent overhead. De formule, voor als je buffers moet reserveren of voortgang moet rapporteren:

import 'dart:convert';
int encodedLength(int n) => (n + 2) ~/ 3 * 4;
void main() {
  print(encodedLength(100000)); // 133336
}

Snelheid is niet de beperking. De encoder is een enkele doorloop van een opzoektafel, en verwerkt megabytes in milliseconden. De beperkingen zijn de groottebelasting zelf, die op de draad en in het geheugen wordt geheven, en het feit dat de gecodeerde vorm een tekenreeks is. Houd beide in het achterhoofd op schaal: voor payloads die groot kunnen worden, stream de codering zoals hierboven getoond, in plaats van één grote lijst en één grote tekenreeks op te bouwen, en bij herhaalde overdrachten van dezelfde data, vraag of het kanaal een binaire modus heeft, want 33 procent is een permanente toeslag die geen algoritme terugstort.

De opdrachtregel-encoder

De VM maakt van de encoder een nette CLI. Dit tooltje leest een bestandargument of de standaard invoer en geeft de codering in het standaardalfabet:

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;
}

Sla dit op als bin/encode.dart en voer dart run bin/encode.dart photo.jpg > photo.b64 uit, of pipe het door met cat config | dart run bin/encode.dart. De metgezel, een decoder die leest en platmaakt, is het eerste voorbeeld in de decodeergids, en samen vormen de twee scripts een klein maar echt handig gereedschap voor het verplaatsen van binair door tekstkanalen.

Valkuilen op de weg naar buiten

  • De codeUnits-val. base64Encode(text.codeUnits) verpakt UTF-16-eenheden, geen bytes. Het werkt voor ASCII, maar gooit bij de eerste code-eenheid boven 255 een ArgumentError. Codeer tekst altijd eerst met een benoemde codering.
  • Alfabet-mismatch. URL-veilige uitvoer aan een consument voeden die het standaardalfabet verwacht, is een 400 die in het verschiet staat. Beslis het alfabet uit de specificatie, codeer één keer en converteer niet achteraf.
  • Padding-aanname. Dart padt altijd. Als de specificatie zonder padding wil, strip dan met replaceAll('=', '') als expliciete stap aan de grens, en zeg dat in de overeenkomst.
  • Tekenset-drift. Latin-1-bytes coderen voor een consument die UTF-8 decodeert, geeft geldige base64 van de verkeerde data. Er gooit niets. De tekst is gewoon fout.
  • Dubbele codering. Een waarde die al base64 is base64-coderen, een token gekopieerd uit een andere config, is de klassieke "decodeert naar nog een muur van base64"-bug.
  • De privacy-illusie. Base64 is een format, geen cijfer. Als het dreigingsmodel een lezer bevat, is het antwoord versleuteling, niet codering.
  • Verouderde pakketten. Het gevestigde jwt-pakket op pub.dev predatert null safety. Voor JWT-werk is crypto plus de paar regels hierboven het onderhouden pad.

Wanneer naar iets anders grijpen

  • Bestandsuploads over HTTP. Gebruik multipart/form-data. Het vervoert ruwe bytes, en zo sla je de 33-procent-belasting volledig over.
  • Grote of herhalende payloads. Comprimeer eerst, codeer daarna: de base64 van gecomprimeerde tekst is dramatisch kleiner dan de base64 van de tekst zelf, en de decomprimerende kant kent het format al.
  • Korte tekst in URLs. Percent-codering is korter voor een handvol tekens, en houdt de waarde voor mensen leesbaar. Data-URIs doen het zelfs standaard voor je.
  • Debug-output en logs. Hex is 50 procent langer dan base64 (twee keer de ruwe grootte, base64 slechts vier derden), maar veel makkelijker te scannen, te diffen en aan een collega over te handigen. Voor binaire fragmenten in logs wint het meestal.

Beste praktijken, de lijst van de encoder

  • Codeer bytes, nooit code-eenheden. Tekst gaat eerst door een benoemde codering.
  • Kies het alfabet uit de specificatie van de consument, vóór je de aanroep schrijft.
  • Strip padding alleen waar de specificatie zonder padding zegt, als een zichtbare stap aan de grens.
  • Noem de tekenset expliciet in de overeenkomst. Veronderstel niets over de andere kant.
  • Stream alles wat groot kan worden.
  • Behandel base64 als een format voor tekst-alleen-kanalen, nooit als bescherming voor gevoelige data.

Een korte geschiedenis van twee alfabetten

Het format dat je zojuist gebruikte is ouder dan elke Dart-release, en de alfabetkeuzes die je ter beschikking staan werden decennia voordat Dart arriveerde gestandaardiseerd. De korte versie:

  • 1993, RFC 1521: MIME introduceert base64 als content transfer encoding voor e-mail, met het standaardalfabet van 64 tekens en de regellengtelimiet van 76 tekens, waarop dit artikel omwikkelt. De taak van het format, binair door tekstkanalen vervoeren, dateert van hier.
  • 1996, RFC 2045: de MIME-vervanging die de padding- en regellengte-regels van base64 tot de duurzame standaard maakte.
  • 2006, RFC 4648: de codering wordt uit MIME gehaald en op zichzelf gestandaardiseerd, met het URL-veilige alfabet en het advies dat decoders ongeldige invoer moeten weigeren. De twee-alfabet-keus die je in Dart krijgt komt uit dit document.
  • 2015, RFC 7515: JSON Web Signatures specificeren base64url zonder padding, de conventie achter elke JWT.
  • November 2015, Dart 1.13: base64 arriveert in dart:convert. De URL-veilige variant volgt in Dart 1.16 het volgende voorjaar, en de topniveau-aanroepen base64Encode en base64UrlEncode die je hierboven gebruikte landen in Dart 2.0 in 2018.
  • Vandaag, Dart 3.13: beide alfabetten, altijd met padding, op één import afstand, dezelfde strikte en eenvoudige machine sinds 2015.

De 33 procent overhead is sinds 1993 ook niet veranderd. Dat is een eigenschap van de wiskunde, vier symbolen voor drie bytes, en elke implementatie die je ooit zult gebruiken, in elke taal, betaalt hem identiek.

Leuke feiten van de coderingswerkbank

  • De encoder is niet uit te zetten: er is geen vlag in de SDK voor output zonder padding, en daarom is "de pads strippen" altijd jouw code, aan jouw grens, in het open.
  • Eén byte wordt vier tekens: base64Encode([65]) is QQ==. De kortst mogelijke base64-tekenreeks is vier tekens lang, en alleen de eerste twee van die vier dragen informatie. De laatste twee zijn padding.
  • Beide Dart-encoders padden, ook base64UrlEncode. De "zonder padding" in base64url is een consumentenconventie uit RFC 7515, geen eigenschap van het alfabet.
  • Het standaardalfabet is ontworpen als 7-bits afdrukbaar, en het is sindsdien de standaard gebleven. Het feit dat + en / uiteindelijk URL-veilige vervangers kregen is een teken van hoe centraal het werd, geen gebrek.
  • Dezelfde 20 UTF-8-bytes van Héllo Wörld 世界 worden verpakt in SMOpbGxvIFfDtnJsZCDkuJbnlYw=, terwijl de 14 code-eenheden van de tekenreeks de encoder op index 12 zouden laten crashen. Zelfde tekens, twee compleet verschillende outputs, waarvan er één een fout is.
  • PEM-bestanden, de -----BEGIN CERTIFICATE------blokken in elk TLS-certificaat, zijn base64 omwikkeld op 64 tekens met headers, en het format dateert uit 1987, zes jaar voordat MIME base64 voor e-mail publiceerde.

Je hebt nu de complete coderingskant in handen: het API-oppervlak, de bytes-eerst-discipline, de padding- en alfabetbeslissingen, en de werkende patronen voor JWTs, data-URIs, bestanden, HTTP, MIME, configuratie, streams en de shell. De omgekeerde richting, één van deze tekenreeksen uit elkaar halen, met al de strengheid van de decoder, de percent-escape-verrassing en de reparatietools, staat in de Base64-decodeergids, verlinkt hieronder.

Laatst bijgewerkt: 2026-10-06

Gerelateerd artikel: Base64-decodering in Dart: een complete gids