> ## Content Index
> Fetch the complete content index at: https://www.tool-cloud.com/blog/fr/llms.txt
> Use this file to discover other available public pages before exploring further.

# Comment convertir du texte en Base64 en JavaScript (et le décoder)
- URL: https://www.tool-cloud.com/blog/fr/comment-convertir-du-texte-en-base64-en-javascript-et-le-decoder/
- Published: 2026-10-14T18:18:34.000Z
- Updated: 2026-10-14T18:28:56.000Z
- Description: La ligne de code qui fonctionne, celle qui génère une erreur, et pourquoi — ainsi que l’aller-retour sûr pour l’UTF-8, les méthodes natives de 2025 et les différences avec Node.js.
- Author: Tool Cloud Team
- Tags: Développeurs, Guides

Pour encoder une chaîne en Base64 en JavaScript, appelez `btoa('Hello, world!')`, qui renvoie `'SGVsbG8sIHdvcmxkIQ=='`. Cette ligne unique ne fonctionne toutefois que pour le texte ASCII et Latin-1 : dès que vous passez un émoji, un accent ou un caractère chinois, elle lance `InvalidCharacterError`. Ce guide explique pourquoi cela se produit et présente l’aller-retour sûr pour l’UTF-8 qui corrige le problème, y compris les nouvelles méthodes natives de 2025.

## Base64 en une ligne : btoa() et atob()

La réponse la plus rapide : encodez avec `btoa('Hello, world!')`, décodez avec `atob('SGVsbG8sIHdvcmxkIQ==')`. Tous deux vérifiés : `btoa('a')` renvoie `'YQ=='`, et `atob('SA==')` renvoie `'S'`.

Ce que [btoa()](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa) fait réellement est de traiter votre chaîne comme une « chaîne binaire », c’est-à-dire une chaîne où chaque caractère représente exactement un octet de données binaires, puis d’encoder ces octets en Base64\. Le cas d’utilisation mentionné par MDN concerne les données provoquant des problèmes de transmission, comme les caractères de contrôle ASCII (0–31), que vous souhaitez faire passer à travers un canal uniquement textuel.

Cette ligne unique suffit lorsque votre texte est en ASCII : le point de code de chaque caractère doit être inférieur à 256, et selon MDN, la correspondance octet-point de code n’est fiable que jusqu’à 0x7F. La plage 0x80–0xFF fonctionne techniquement, mais elle repose sur le comportement d’encodage Latin-1 qui n’est pas portable entre les environnements. Une bonne règle : tout texte non ASCII nécessite la méthode UTF-8 décrite ci-dessous.

## Pourquoi btoa() lance InvalidCharacterError sur les émojis, accents et CJK

Le Base64 est un encodage binaire, pas un encodage de texte. [Le glossaire de MDN](https://developer.mozilla.org/en-US/docs/Glossary/Base64) qualifie l’habitude de passer du texte arbitraire ou du HTML à `btoa()` d’une idée reçue courante : `btoa`/`atob` précèdent les tableaux typés, ils utilisent donc des chaînes pour représenter des octets. Le problème commence lorsque votre chaîne ne contient pas un octet par caractère.

Les chaînes JavaScript sont en UTF-16, donc une unité de code fait toujours deux octets, et les caractères hors du BMP (comme les émojis) prennent quatre octets sous forme de paire de substitution ; l’UTF-8 utilise de un à quatre octets par point de code. `btoa()` et `atob()` ne fonctionnent qu’avec des caractères sur un seul octet (plage Latin-1). Essayez d’encoder quelque chose de plus large et vous obtenez cette erreur exacte :

```
DOMException: Failed to execute 'btoa' on 'Window':
The string to be encoded contains characters outside of the Latin1 range

```

Le cas de rupture est trivial à reproduire : `btoa('✓')` lance une erreur, tout comme `btoa('a Ā 𐀀 文 🦄')`. Les émojis, les lettres accentuées au-delà du Latin-1 et les caractères CJK se situent tous au-dessus de 0xFF, aucun ne respecte donc l’hypothèse d’un octet par caractère. `'✓'` est U+2713, bien au-dessus de 0xFF, donc `btoa()` refuse plutôt que de corrompre silencieusement vos données. Ce refus est probablement la meilleure fonctionnalité de l’API : il échoue bruyamment au lieu de produire du mojibake que vous découvririez des semaines plus tard.

Un dernier point utile à connaître avant de corriger cela : le Base64 augmente la taille des données d’environ 33 % par rapport aux octets bruts. Cela convient pour les petites chaînes, les jetons et les URI de données, mais constitue une raison valable de ne pas encoder en Base64 de gros payloads : encodez à la frontière dont vous avez besoin, pas partout.

![Un ruban bleu doux en 3D entrant par la gauche et se divisant en deux chemins : un brin forme des groupes compacts soignés de…](https://www.tool-cloud.com/blog/fr/content/images/2026/10/javascript-base64-encode-utf8-split.webp)

Un flux de données, deux empreintes en octets : clusters multi-octets contre octets isolés.

### Le cas limite du demi-codet isolé (et String.isWellFormed())

La plupart des articles l’ignorent, mais cela pose problème : une chaîne UTF-16 contenant un demi-codet isolé (moitié d’une paire de substitution, souvent due à un bug de découpage) est « mal formée ». Selon [le guide de web.dev](https://web.dev/articles/base64-encoding), `TextDecoder` remplace silencieusement par U+FFFD par défaut. Avant l’encodage, vérifiez la conformité avec `String.prototype.isWellFormed()`, ou capturez l’erreur `URIError` que `encodeURIComponent()` lance sur les demi-codets isolés, puis décidez explicitement : rejeter les données, activer le remplacement délibérément, ou lancer une exception pour analyse ultérieure.

## La bonne méthode : TextEncoder → octets UTF-8 → Base64

La bonne correction consiste à convertir d’abord votre chaîne en octets UTF-8 avec `TextEncoder`, puis à encoder ces octets en Base64 au lieu de la chaîne. `new TextEncoder().encode(str)` transforme n’importe quelle chaîne JavaScript en un `Uint8Array` d’octets UTF-8 (TextEncoder ne parle que l’UTF-8). Au retour, `new TextDecoder()` utilise par défaut l’UTF-8 et inverse l’opération avec précision. Notez ce que `atob()` vous donne ici : une chaîne binaire, un caractère par octet, pas du texte UTF-8\. C’est pourquoi le côté décodage a besoin de `TextDecoder` pour retransformer les octets en texte lisible.

### Fonctions utilitaires bytesToBase64() et base64ToBytes() (code à copier-coller)

Voici [l’aller-retour canonique de MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa), qui fonctionne dans tous les navigateurs prenant en charge `TextEncoder` (IE exclu) :

```js
function bytesToBase64(bytes) {
  const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join('');
  return btoa(binString);
}

function base64ToBytes(base64) {
  const binString = atob(base64);
  return Uint8Array.from(binString, (m) => m.codePointAt(0));
}

```

### Vérifiez avec un aller-retour complet

L’encodage d’une chaîne devient une seule ligne :

```js
const encoded = bytesToBase64(new TextEncoder().encode('a Ā 𐀀 文 🦄'));
// 'YSDEgCDwkICAIOaWhyDwn6aE'

```

Le décodage l’inverse :

```js
const decoded = new TextDecoder().decode(base64ToBytes(encoded));
// 'a Ā 𐀀 文 🦄'

```

L’aller-retour vérifié par web.dev confirme le même schéma : `'hello⛳❤️🧀'` encode en `'aGVsbG/im7PinaTvuI/wn6eA'` et redonne exactement l’original, émojis inclus.

### Évitez l’astuce unescape(encodeURIComponent())

Vous trouverez `btoa(unescape(encodeURIComponent(str)))` copié partout. Cela fonctionne, mais `unescape()` relève de l’Annexe B, dépréciée depuis ECMAScript 3\. Le nouveau code devrait utiliser `TextEncoder` à la place : c’est explicite, standard, et ne dépend pas d’une globale dépréciée.

## La méthode 2025 : Uint8Array.toBase64() et Uint8Array.fromBase64()

Depuis septembre 2025, JavaScript dispose de méthodes Base64 natives directement sur `Uint8Array`, de sorte que les fonctions utilitaires de chaîne d’octets ci-dessus ne sont plus la seule option. La [proposition Base64 de TC39](https://github.com/tc39/proposal-arraybuffer-base64/blob/main/README.md) a atteint le stade 4 et fait partie du langage ; la justification de TC39 est que le Base64 n’est pas un encodage de texte, donc TextEncoder/TextDecoder sont conceptuellement les mauvais outils pour cela.

Selon [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global%5FObjects/Uint8Array/toBase64), ces méthodes sont considérées comme « nouvellement disponibles » dans la norme Baseline pour les navigateurs pérennes. Vérifiez vos environnements cibles avant de déployer : si vous devez prendre en charge d’anciens navigateurs ou des versions anciennes de Node, conservez la solution de repli `TextEncoder` \+ `btoa`. MDN recommande ces méthodes plutôt que `btoa()`/`atob()` lorsque vous disposez déjà d’un objet `Uint8Array`, car elles évitent de créer une chaîne brute contenant les octets bruts.

### Encodage : bytes.toBase64()

```js
const b64 = new TextEncoder().encode('Hello, world!').toBase64();
// 'SGVsbG8sIHdvcmxkIQ=='

```

Une seule conversion UTF-8, un appel de méthode, et c’est terminé.

### Décodage : Uint8Array.fromBase64()

```js
const text = new TextDecoder().decode(Uint8Array.fromBase64(b64));
// 'Hello, world!'

```

MDN indique que `fromBase64()` est préférable à `atob()` car il renvoie un véritable tableau d’octets, sauf si les données décodées sont destinées à être traitées comme du texte ASCII. Il n’accepte que l’alphabet base64 (A–Z, a–z, 0–9, plus `+/` ou `-_`), un padding facultatif `=`, et ignore les espaces ASCII ; il lance une erreur `SyntaxError` en cas de caractère hors alphabet.

### Options : alphabet, omitPadding, lastChunkHandling

Le [paquet d’options de la spécification](https://tc39.es/proposal-arraybuffer-base64/) vous offre un contrôle précis :

| Option            | Valeurs                                               | Ce qu’elle fait                                                                                                    |
| ----------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| alphabet          | 'base64' (par défaut), 'base64url'                    | Comparaison +// vs \-/\_                                                                                           |
| omitPadding       | booléen                                               | Supprime le padding \= final : new Uint8Array(\[72\]).toBase64() devient 'SA==', avec omitPadding qui passe à 'SA' |
| lastChunkHandling | 'loose' (par défaut), 'strict', 'stop-before-partial' | Tolérance du décodeur pour le dernier chunk                                                                        |

`'loose'` tolère l’absence de padding et les espaces. `'strict'` exige des chunks de 4 caractères exacts avec des bits de débordement mis à zéro, ce qui est idéal pour valider des données non fiables. `'stop-before-partial'` est conçu pour le streaming. Le mode par défaut (laxiste) tolère également les bits de débordement non nuls, que le mode strict rejette.

## Base64 vs base64url : quel alphabet choisir ?

Le base64 standard utilise `+` et `/` ainsi que le padding `=`, et convient parfaitement aux `data:` URLs car celles-ci ne comportent ni segments de chemin ni chaînes de requête. Le base64url (RFC 4648 §5) remplace `-` et `_` et omet généralement le padding ; il est obligatoire lorsque la sortie est intégrée dans une URL : les JWT utilisent par exemple le base64url pour leurs trois segments.

### Quand utiliser le base64url

Utilisez le base64url lorsque la chaîne encodée fait partie d’un chemin d’URL ou d’un paramètre de requête, où `+` et `/` nécessiteraient un échappement (et où le padding `=` encombre les chaînes de requête). Privilégiez le base64 standard pour les data URIs, pour intégrer des octets dans des payloads JSON, ou pour tout usage qui n’est pas une URL.

### Comment produire du base64url

Trois méthodes, selon votre environnement :

- Navigateurs modernes : `bytes.toBase64({ alphabet: 'base64url' })`
- Node 16+ : `Buffer.from(str).toString('base64url')`
- Post-traitement : prenez la sortie standard et remplacez `+` par `-`, `/` par `_`, puis supprimez le padding `=`

Une subtilité utile à connaître : la RFC 4648 impose aux encodeurs de mettre à zéro les bits de débordement sans données du dernier chunk, et les décodeurs stricts peuvent lancer une erreur s’ils ne sont pas à zéro. Le glossaire de MDN donne l’exemple de `'VR=='`, qui correspond au même octet que `'VQ=='` mais avec des bits de padding incorrects. Générez du base64 avec un encodeur conforme et ce problème ne se pose jamais ; si vous écrivez votre propre encodeur, il peut survenir.

## Encodage d’un fichier ou d’une image en Base64 (data URLs)

Pour les fichiers, la voie navigateur consiste à utiliser `FileReader` avec `readAsDataURL()`, ce qui produit une data URL complète, puis à supprimer le préfixe pour obtenir le base64 brut. Pour les images déjà rendues dans un canvas, `toDataURL('image/png')` effectue cette opération en un seul appel.

### FileReader.readAsDataURL() → data URL → base64 brut

```js
function fileToDataURL(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.readAsDataURL(file);
  });
}

const dataUrl = await fileToDataURL(fileInput.files[0]);
const rawBase64 = dataUrl.replace(/^data:\w+\/\w+;base64,/, '');

```

### canvas.toDataURL() pour les images

Si vous avez dessiné une image sur un canvas (redimensionnement, recadrage, etc.), contournnez complètement FileReader :

```js
const dataUrl = canvas.toDataURL('image/png');

```

La suppression du préfixe s’applique également si vous avez besoin de la chaîne base64 pure.

### Conversion d’une data URL vers des octets

Le sens inverse nécessite un fetch suivi d’un ArrayBuffer. L’exemple de MDN montre une data URL construite à partir de `new Uint8Array([0,1,2])`, soit `'data:application/octet-stream;base64,AAEC'`, et vous pouvez récupérer les octets ainsi :

```js
const res = await fetch(dataUrl);
const bytes = new Uint8Array(await res.arrayBuffer());
// [0, 1, 2]

```

Et voici le rappel essentiel pour lequel cet article existe : n’appelez pas `btoa()` sur du texte arbitraire ou du HTML pour construire des data URLs. C’est un encodeur octet à octet, et une entrée non Latin-1 provoquera une erreur.

## Node.js : Buffer.from(str, 'base64') — et sa différence critique

Node possède ses propres idiomes qui contournent entièrement l’étape TextEncoder : `Buffer.from('Hello, world! 🌍').toString('base64')` gère Unicode automatiquement, car Buffer travaille directement sur les octets dès le départ. Décodez avec `Buffer.from(encoded, 'base64').toString('utf8')`.

Autres formes utiles : `Buffer.from(str).toString('base64url')` (Node 16+), et lecture de fichiers complets via `fs.readFileSync('image.png').toString('base64')`.

```js
const encoded = Buffer.from('Hello, world! 🌍').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf8');

```

### Node ne valide pas votre base64 (échecs silencieux)

Voici ce qui surprend souvent : le décodeur base64 de Node ne valide pas l’entrée. `Buffer.from('!!!!', 'base64').toString()` renvoie `''` sans erreur, et `Buffer.from('aGVsbG8!!!', 'base64')` ignore silencieusement les caractères invalides et renvoie `'hello'`. Comparez cela à `atob('aGVsbG8!!!')`, qui lève une erreur `InvalidCharacterError`. Si le base64 provient d’utilisateurs, d’une API ou d’un tiers, validez-le avant le décodage sous Node, ou utilisez `Uint8Array.fromBase64()` avec `lastChunkHandling: 'strict'` là où les environnements le permettent.

### btoa/atob sont-elles dépréciées ? Navigateurs vs Node

Cette situation est réellement contradictoire, voici donc la résolution honnête. Dans les navigateurs, [MDN indique que btoa() et atob()](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa) sont largement disponibles depuis juillet 2015 et ne sont pas dépréciées. Sous Node, les [définitions de types](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/58795) les marquent comme `@deprecated` avec le commentaire indiquant qu’« elles ne devraient jamais être utilisées dans du nouveau code », recommandant plutôt `Buffer.from(str, 'base64')`.

Une bonne règle : il s’agit d’une API legacy, non supprimée. Elle reste acceptable dans le code navigateur, mais privilégiez `Buffer` dans le code spécifique à Node. Par consensus communautaire (et non par garantie de spécification), `btoa`/`atob` constituent également le choix pratique multi-environnements si vous souhaitez un seul chemin de code fonctionnant inchangé sous les navigateurs, Deno et Node sans dépendances tierces.

## Que faut-il vraiment utiliser ?

Si vous retenez une seule recommandation de cet article, ce sont les trois lignes ci-dessous. Conservez `btoa`/`atob` pour l’ASCII pur et les bases de code héritées, et utilisez l’aide `bytesToBase64` comme solution de repli navigateur jusqu’à ce que `toBase64()` couvre l’ensemble de votre audience.

```js
// Modern browsers (2025+)
const enc = new TextEncoder().encode(str).toBase64();
const dec = new TextDecoder().decode(Uint8Array.fromBase64(b64));

// Browser fallback (MDN helper)
const encFallback = bytesToBase64(new TextEncoder().encode(str));

// Node (validate input first if it isn't yours)
const encNode = Buffer.from(str).toString('base64');

```

Avant de déployer, vérifiez votre sortie avec un aller-retour rapide dans un outil navigateur. Collez `'Hello, world!'` dans [l’Encodeur / Décodeur Base64 gratuit de Tool Cloud](https://www.tool-cloud.com/fr/dev/base64%5Fencoder/), confirmez que vous obtenez bien `'SGVsbG8sIHdvcmxkIQ=='`, puis décodez-le à nouveau et vérifiez qu’il est identique. Vous trouverez également un convertisseur dédié [Texte vers Base64](https://www.tool-cloud.com/fr/general/text%5Fto%5Fbase64/) et un autre [Base64 vers Texte](https://www.tool-cloud.com/fr/general/base64%5Fto%5Ftext/) ; les fichiers sont supprimés automatiquement et aucune installation n’est requise.

## Questions fréquentes

### Pourquoi btoa() échoue-t-il sur les émojis mais fonctionne-t-il sur le texte anglais ?

btoa() traite chaque caractère comme un seul octet et exige que chaque point de code soit inférieur à 256 (de manière fiable seulement jusqu’à 0x7F). Les émojis, les caractères accentués et les textes CJK nécessitent plusieurs octets, ce qui déclenche une DOMException : InvalidCharacterError. Convertissez d’abord en octets UTF-8 avec TextEncoder, puis encodez ces octets.

### btoa() est-il déprécié ?

Non dans les navigateurs — MDN indique que btoa() et atob() sont largement disponibles depuis juillet 2015\. Cependant, les définitions de types de Node les marquent comme dépréciées au profit de Buffer.from(str, 'base64') dans le code spécifique à Node. Il s’agit d’une API héritée, non supprimée.

### Comment encoder en Base64 du texte Unicode (accents, chinois, émojis) ?

Utilisez new TextEncoder().encode(str) pour obtenir des octets UTF-8, puis encodez ces octets (btoa() via une fonction utilitaire de chaîne d’octets, ou Uint8Array.toBase64() dans les navigateurs modernes). Pour décoder, utilisez Uint8Array.fromBase64() ou atob() pour récupérer les octets, puis new TextDecoder().decode(bytes).

### Quelle est la différence entre le base64 et le base64url ?

base64url (RFC 4648 §5) utilise '-' et '\_' au lieu de '+' et '/', et omet généralement le remplissage '='. Utilisez base64url lorsque la sortie est destinée aux URL ou aux JWT ; le Base64 standard convient bien aux data: URLs, qui ne comportent pas de segments de chemin ni de chaînes de requête.

### Pourquoi Node.js ne génère-t-il pas d’erreur sur un Base64 invalide ?

Buffer.from(str, 'base64') de Node ne valide pas l’entrée : il ignore silencieusement les caractères invalides, donc Buffer.from('aGVsbG8!!!', 'base64').toString() renvoie 'hello' sans erreur. Dans les navigateurs, atob() lance InvalidCharacterError sur la même entrée. Validez le Base64 non fiable avant le décodage dans Node.