Intermédiaire 8 min de lecture 25 janvier 2025

Base64 et UTF‑8 : encodage, décodage et pièges courants

Vous échangez des chaînes encodées, des JSON signés, des images en data URI. Tout semble correct, mais l’API refuse votre payload, une image n’apparaît pas, une comparaison échoue. Le problème vient souvent d’un mauvais aller‑retour entre UTF‑8 (caractères → octets) et base64 (octets → texte sûr).

Qu’est‑ce que base64 et UTF‑8 ?

UTF‑8 convertit des caractères en octets. Base64 convertit des octets en texte ASCII sûr. Mélanger leur rôle ou l’ordre des opérations produit des bugs subtils.

Voici les notions essentielles à connaître :

1 UTF‑8 en bref

Encodage variable (1 à 4 octets) couvrant tout Unicode, rétro‑compatible ASCII.

ASCII (0x20–0x7E), Multi‑octets (é = C3 A9), BOM optionnel (EF BB BF)

2 Base64 en bref

Représentation texte d’octets, utilise 64 symboles + signe "=" pour le padding.

Alphabet A–Z a–z 0–9 + /, Padding "=", blocs de 4 caractères

3 Variantes et options Base64

Les différences qui cassent l’interopérabilité :

base64url (RFC 4648) - remplace +/ par -_ et parfois sans "="
MIME (RFC 2045) - retour à la ligne tous les 76 caractères
Sans padding - courant pour JWT/JWS
Data URI - "data:...;base64,..."

4 Éléments techniques influents

Ce qui modifie les résultats sans s’en rendre compte :

BOM UTF‑8 (EF BB BF) ajouté/retiré
TextEncoder/TextDecoder, iconv, mbstring
Entêtes HTTP "Content‑Type; charset=UTF‑8"
Normalisation Unicode (NFC/NFKC)

Problèmes classiques

btoa/atob sur du texte Unicode

Dans le navigateur, btoa/atob attend un binaire Latin‑1. Sans TextEncoder, les caractères non‑ASCII cassent.

Tests unitaires incohérents entre environnements

Node Buffer vs navigateur, base64url vs standard, fin de ligne MIME: les sorties ne correspondent plus.

Padding et retours à la ligne

"Incorrect padding" ou erreurs de décodage à cause de "=" manquants/extras ou de lignes coupées.

Mauvais encodage d’entrée

Chaîne initiale en Latin‑1 alors que vous pensez UTF‑8: le base64 ne sera pas identique.

Exemple de problème courant :

# Même texte, encodage d’entrée différent
string1 = base64_utf8("café") # "Y2Fmw6k="
string2 = base64_latin1("café") # "Y2Fm6Q=="
assert string1 == string2 # ❌ Échec

Symptômes qui doivent vous alerter

🚨 Signaux d'alarme

!
API renvoyant "Invalid base64" ou "Incorrect padding"
!
Une image en data URI n’apparaît pas ou est corrompue
!
Comparaisons de chaînes base64 différentes entre deux machines
!
Un JWT/JWS/JWE invalide à cause d’une variante non compatible (base64url)
!
Des retours à la ligne insérés cassent le décodage (flux MIME)

Comment les détecter

Solution recommandée : Clean ASCII

Clean ASCII permet d’inspecter vos chaînes, voir les octets réels UTF‑8 et repérer ce qui perturbe vos encodages base64. Collez votre texte, vérifiez les octets, encodez/décodez proprement et évitez les doubles conversions.

✅ Détection automatique

BOM, octets invalides, retours à la ligne, padding manquant/excessif

📊 Analyse complète

Aperçu UTF‑8, base64 standard et base64url, longueurs et blocs

🧹 Conversion fiable

Chaîne → UTF‑8 → base64 et l’inverse, sans perte ni corruption

💾 Export propre

Résultats prêts pour API, JWT, data URI, stockage

Autres méthodes de détection

Affichage dans l'éditeur

Affichez l’encodage du fichier (UTF‑8), l’état du BOM, les fins de ligne
Utilisez des extensions qui montrent/convertissent base64 et data URI

En ligne de commande (Unix)

# Encodage UTF‑8 → base64 sans retour à la ligne
printf 'café' | base64 | tr -d '\n'
# Décoder du base64 et inspecter les octets
echo 'Y2Fmw6k=' | base64 -d | xxd -g1
# Vérifier charset détecté par le système
file -I fichier.txt
# Convertir d’un encodage à un autre
iconv -f latin1 -t utf-8 fichier.txt | base64

En code

JavaScript

const enc = new TextEncoder();
const dec = new TextDecoder('utf-8');
const b64 = btoa(String.fromCharCode(...enc.encode(str)));
const s = dec.decode(Uint8Array.from(atob(b64), c => c.charCodeAt(0)));

Python

import base64
b64 = base64.b64encode(s.encode('utf-8')).decode('ascii')
s2 = base64.b64decode(b64).decode('utf-8')

Excel / Google Sheets

# Google Apps Script (Sheets)
Utilities.base64Encode(Utilities.newBlob(str, 'text/plain; charset=UTF-8').getBytes())

# Power Query (Excel M)
Binary.ToText(Text.ToBinary(str, TextEncoding.Utf8), BinaryEncoding.Base64)

Nettoyer et prévenir

🚀 Solution rapide avec Clean ASCII

Avant d’écrire des scripts, vérifiez en un clic votre texte, ses octets UTF‑8 et la sortie base64 pour un envoi sûr.

Inspection des octets
Conversion UTF‑8 ⇄ Base64
Export prêt pour API

Méthodes techniques avancées

🔧 Normaliser

Imposez UTF‑8 partout (fichiers, DB, HTTP, JSON)
Évitez le BOM en UTF‑8 pour les flux (EF BB BF)
Uniformisez les fins de ligne (gitattributes, dos2unix)

🧹 Filtrer

Centralisez des fonctions toBase64Utf8() et fromBase64Utf8()
Validez la variante (standard vs base64url) et le padding
Bloquez les retours à la ligne dans les blobs base64 destinés aux API

⚙️ Automatiser

Hooks pre-commit pour vérifier UTF‑8 et absence de BOM
Tests de round‑trip (str → UTF‑8 → base64 → UTF‑8)
Linting CI sur les payloads (regex base64/base64url)

Checklist rapide

Fichiers et API en UTF‑8 sans BOM
Une variante base64 décidée (standard ou URL‑safe) pour tout le projet
Fonctions utilitaires d’encodage/décodage centralisées
Tests de round‑trip sur les données critiques (JWT, pièces jointes)
Validation du padding et absence de retours à la ligne intempestifs
Documentation claire sur charsets, variantes base64 et EOL

Conclusion

Base64 n’est pas un encodage de caractères, c’est un emballage d’octets. UTF‑8 convertit vos caractères en octets. En respectant cet ordre et la variante adéquate, vous évitez les erreurs récurrentes.

Standardisez UTF‑8, choisissez votre base64 (standard/url‑safe), contrôlez le padding et automatisez les vérifications. Vos échanges deviennent fiables.

Maîtrisez base64 et UTF‑8 maintenant

Utilisez notre outil pour analyser les octets, encoder proprement et fiabiliser vos flux.

Analyser/encoder mon texte