Codificación y decodificación de cadenas Base64 en Node.js

La codificación Base64 es una forma de convertir datos (generalmente binarios) en el juego de caracteres ASCII. Es importante mencionar aquí que Base64 no es un cifrado o c...

¿Qué es la codificación Base64? {#qué es la codificación base64}

La codificación Base64 es una forma de convertir datos (generalmente binarios) en el juego de caracteres ASCII. Es importante mencionar aquí que Base64 no es una técnica de cifrado o compresión, aunque a veces se puede confundir con el cifrado debido a la forma en que parece ocultar los datos. De hecho, el tamaño de una información codificada en Base64 es 1,3333 veces el tamaño real de los datos originales.

Base64 es la técnica de codificación base más utilizada, siendo Base16 y Base32 los otros dos esquemas de codificación más utilizados.

¿Cómo funciona Base64?

La conversión de datos a base64 es un proceso de varios pasos. Así es como funciona para cadenas de texto:

  1. Calcule la versión binaria de 8 bits del texto de entrada
  2. Reagrupar la versión de 8 bits de los datos en varios fragmentos de 6 bits
  3. Encuentra la versión decimal de cada uno de los fragmentos binarios de 6 bits
  4. Encuentre el símbolo Base64 para cada uno de los valores decimales a través de una tabla de búsqueda Base64

Para una mejor comprensión de este concepto, echemos un vistazo a un ejemplo.

Supongamos que tenemos la cadena "Go win" y queremos convertirla en una cadena Base64. El primer paso es convertir esta cadena en binario. La versión binaria de "Go win" es:

1
01000111  01101111  00100000  01110111  01101001  01101110

Puede ver aquí que cada carácter está representado por 8 bits. Sin embargo, como dijimos anteriormente, Base64 convierte los datos en forma binaria de 8 bits en fragmentos de 6 bits. Esto se debe a que el formato Base64 solo tiene 64 caracteres: 26 letras del alfabeto en mayúsculas, 26 letras del alfabeto en minúsculas, 10 caracteres numéricos y los símbolos "+" y "/" para la nueva línea.

Base64 no usa todos los caracteres especiales ASCII, sino solo estos pocos. Tenga en cuenta que algunas implementaciones de Base64 usan caracteres especiales diferentes a "+" y "/".

Volviendo al ejemplo, dividamos nuestros datos de 8 bits en fragmentos de 6 bits.

1
010001  110110  111100  100000  011101  110110  100101  101110

No siempre podrá dividir los datos en conjuntos completos de 6 bits, en cuyo caso tendrá que lidiar con el relleno.

Ahora, para cada fragmento de arriba, tenemos que encontrar su valor decimal. Estos valores decimales se dan a continuación:

1
2
3
4
5
6
7
8
9
Binary  Decimal
010001  17
110110  54
111100  60
100000  32
011101  29
110110  54
100101  37
101110  46

Finalmente, tenemos que buscar el valor Base64 para cada uno de los decimales que acabamos de calcular a partir de datos binarios. La tabla de codificación Base64 se ve así:

Tabla de consulta de decimal a base64

Aquí puedes ver que el decimal 17 corresponde a "R", y el decimal 54 corresponde a "2", y así sucesivamente. Usando esta tabla de codificación, podemos ver que la cadena "Go win" está codificada como "R28gd2lu" usando Base64. Puede usar cualquier convertidor de texto en línea a Base64 para verificar este resultado.

¿Por qué usar la codificación Base64? {#por qué usar la codificación base64}

Enviar información en formato binario a veces puede ser riesgoso, ya que no todas las aplicaciones o sistemas de red pueden manejar archivos binarios sin procesar. Por otro lado, el juego de caracteres ASCII es ampliamente conocido y muy simple de manejar para la mayoría de los sistemas.

Por ejemplo, los servidores de correo electrónico esperan datos textuales, por lo que normalmente se utiliza ASCII. Por lo tanto, si desea enviar imágenes o cualquier otro archivo binario a un servidor de correo electrónico, primero debe codificarlo en formato de texto, preferiblemente ASCII. Aquí es donde la codificación Base64 resulta extremadamente útil para convertir datos binarios a los formatos correctos.

Codificación de cadenas Base64 con Node.js

La forma más sencilla de codificar cadenas Base64 en Node.js es a través del objeto Buffer. En Node.js, Buffer es un objeto global, lo que significa que no necesita usar la instrucción require para usar el objeto Buffer en sus aplicaciones.

Internamente, Buffer es una matriz inmutable de números enteros que también es capaz de realizar muchas codificaciones/decodificaciones diferentes. Estos incluyen hacia/desde codificaciones UTF-8, UCS2, Base64 o incluso Hex. A medida que escribe código que trata y manipula datos, es probable que utilice el objeto Buffer en algún momento.

Echa un vistazo al siguiente ejemplo. Aquí codificaremos una cadena de texto en Base64 usando el objeto Buffer. Guarde el siguiente código en un archivo "encode-text.js"

1
2
3
4
5
6
7
'use strict';

let data = 'wikihtp.com';
let buff = new Buffer(data);
let base64data = buff.toString('base64');

console.log('"' + data + '" converted to Base64 is "' + base64data + '"');

En el script anterior, creamos un nuevo objeto de búfer y le pasamos nuestra cadena que queremos convertir a Base64. Luego llamamos al método "toString" en el objeto de búfer que acabamos de crear y lo pasamos "base64" como parámetro. El método "toString" con "base64" como parámetro devolverá datos en forma de cadena Base64. Ejecute el código anterior, verá el siguiente resultado.

1
2
$ node encode-text.js
"wikihtp.com" converted to Base64 is "c3RhY2thYnVzZS5jb20="

En el resultado, podemos ver la contraparte de Base64 para la cadena que convertimos a Base64.

Decodificación de cadenas Base64 con Node.js

Decodificar una cadena Base64 es bastante similar a codificarla. Debe crear un nuevo objeto de búfer y pasar dos parámetros a su constructor. El primer parámetro son los datos en Base64 y el segundo parámetro es "base64". Luego, simplemente tiene que llamar a "toString" en el objeto de búfer, pero esta vez el parámetro pasado al método será "ascii" porque este es el tipo de datos al que desea que se conviertan sus datos de Base64. Eche un vistazo al siguiente fragmento de código como referencia.

1
2
3
4
5
6
7
'use strict';

let data = 'c3RhY2thYnVzZS5jb20=';
let buff = new Buffer(data, 'base64');
let text = buff.toString('ascii');

console.log('"' + data + '" converted from Base64 to ASCII is "' + text + '"');

Agregue los datos al archivo "ascii.js" y guárdelo. Aquí hemos usado "Tm8gdG8gUmFjaXNt" como datos de entrada de Base64. Cuando se decodifiquen estos datos, debería mostrar "No al racismo". Esto se debe a que del último ejemplo sabemos que "No al Racismo" es igual a "Tm8gdG8gUmFjaXNt". Ejecute el código anterior con Node.js. Mostrará la siguiente salida.

Codificación de datos binarios en cadenas Base64

Como se mencionó al comienzo del artículo, el propósito principal de la codificación Base64 es convertir datos binarios en formato de texto. Veamos un ejemplo en el que convertiremos una imagen (datos binarios) en una cadena Base64. Echa un vistazo al siguiente ejemplo.

1
2
3
4
5
6
7
8
'use strict';

const fs = require('fs');

let buff = fs.readFileSync('stack-abuse-logo.png');
let base64data = buff.toString('base64');

console.log('Image converted to base 64 is:\n\n' + base64data);

En el código anterior, cargamos una imagen en el búfer mediante el método readFileSync() del módulo fs. El resto del proceso es similar a crear una cadena Base64 a partir de una cadena ASCII normal.

Cuando ejecute el código anterior, verá el siguiente resultado.

1
2
3
4
$ node encode-image.js
Image converted to Base64 is:

iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAYAAABlcqYFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAADuUlEQVQ4EbVUTUtcZxR+7ufkXp1SZ4iZRE1EDVQRnTAhowsZMFm40I2rNqUIIev8hvoPQroQXBTqwiAWcd0EglEhiZNajVZrQGXAWAzaZpzMnZn7lXPeeIe5DaWb9Ax33vOec8/znI/3vVI6nfbxP4v8b/iSJIGfzyGfkPi+D13XUalUBL6qqmIvy5+8WuX/r2RCkUzAoIuLi2hqaoLrutjb28P6+josyxJkiqJA07SQXiqVwHaOZYx/itLc3Px9YIxEIlheXsbExATGxsYwMjIiwEdHRwXA/Pw8EokEcrkcDg4OYJomVlZWMDU1JSqfmZlBR0cHbNsOtVoNCHjlTFiSySQMwxAVxONxQbi0tIRMJoPe3l5MT0+jtbUVg4ODYGImY18qlcL4+DhisZjoggCjv1C7uOyenh7Mzs5iY2ND6FQpdnd3sba2JloSjUYxPDyM/v5+TE5OYn9/X9jZtrOzg+3t7WqyAUmoEu419/+HBw9E+eVymbJqAJP39fWBCR3HEU+hUMDQ0JCYGc8um81iYGAAjY2N8DwvwBdraCY8tHhDA1Y3N9Hd3S2yvH37O7RcbsF7AuUsD9+8wdOFBTx/8QJtbW1C5/nMzc3R0D2UyxXk83lRXcAk1V5GCT5sSUGDbeHxy9/EO98M9OOXzT9wfHISxKC1vR0GHfOtrS2g/SouWwU0Xkggu7qO9PUkJFULnbIQyTm6ewu2hF+vnOIIUQwdGlg8f4QF6wvMWBq+pAkaskSnx4FFVUf0CNpcC797KizXQ4oAHhVdXJJ81F7j6kwUynPHlXDPdFB2fRj+KVK0KvT2rbp3uKYryJU11Cke8qqMuOoioeeJ1MPDYxM36m1cNSq4GdFx58RAWvbx8TrXnK4IgR16Em5GK4iqHi5GHHxLgcSDn97WgZPoND+GGZRpPYH85cgiiRQl1ltXxmFFQ5PuopP8TrW5ZyRcWp7AbmkeZefg5+N6PPnbRJdpw/YlfB0vQiPQZwVdZNtFZEVK6D1VTnccJlXzuqTjvOZiq6Rhj2KqLSJsofOHgIl8+t0/qsfDioxmSUWGjrRFzhYi/5Oynrdl3KXHIZDXtF6hil8R6I9FBV/RvDLnXKxSbAdVYhNeINXBMwmXWCTQGG2Y+Jj+dFrfEmiMAtmeowpo9ojTvkD+A/L1UJUMmiVfkuz6WTyZhFRJAgP33j3bsM5k/Fng68UP21hYJyyxZwLWuS2cKMfUSm3rhD0g4E2g197fwMZ+Bgt8rNe2iP2BhL5dgfFzrx8AfECEDdx45a0AAAAASUVORK5CYII=

Aunque la imagen real es muy pequeña (25x19), la salida sigue siendo bastante grande, en parte porque Base64 aumenta el tamaño de los datos, como mencionamos anteriormente.

Decodificación de cadenas Base64 a datos binarios

El proceso inverso aquí es muy similar a cómo decodificamos cadenas Base64, como vimos en una sección anterior. La mayor diferencia es el destino de salida y cómo se escriben los datos allí. Veamos el ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';

const fs = require('fs');

let data = 'iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAYAAABlcqYFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAA' + 
'CA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0' +
'YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly' +
'93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAg' +
'ICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZm' +
'Y6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAADuUlEQVQ4EbVU' +
'TUtcZxR+7ufkXp1SZ4iZRE1EDVQRnTAhowsZMFm40I2rNqUIIev8hvoPQroQXBTqwiAWcd0EglEhiZNajVZrQGXAWAzaZpzMnZn7lXPeeIe5Da' +
'Wb9Ax33vOec8/znI/3vVI6nfbxP4v8b/iSJIGfzyGfkPi+D13XUalUBL6qqmIvy5+8WuX/r2RCkUzAoIuLi2hqaoLrutjb28P6+josyxJkiqJA' +
'07SQXiqVwHaOZYx/itLc3Px9YIxEIlheXsbExATGxsYwMjIiwEdHRwXA/Pw8EokEcrkcDg4OYJomVlZWMDU1JSqfmZlBR0cHbNsOtVoNCHjlTF' +
'iSySQMwxAVxONxQbi0tIRMJoPe3l5MT0+jtbUVg4ODYGImY18qlcL4+DhisZjoggCjv1C7uOyenh7Mzs5iY2ND6FQpdnd3sba2JloSjUYxPDyM' +
'/v5+TE5OYn9/X9jZtrOzg+3t7WqyAUmoEu419/+HBw9E+eVymbJqAJP39fWBCR3HEU+hUMDQ0JCYGc8um81iYGAAjY2N8DwvwBdraCY8tHhDA1' +
'Y3N9Hd3S2yvH37O7RcbsF7AuUsD9+8wdOFBTx/8QJtbW1C5/nMzc3R0D2UyxXk83lRXcAk1V5GCT5sSUGDbeHxy9/EO98M9OOXzT9wfHISxKC1' +
'vR0GHfOtrS2g/SouWwU0Xkggu7qO9PUkJFULnbIQyTm6ewu2hF+vnOIIUQwdGlg8f4QF6wvMWBq+pAkaskSnx4FFVUf0CNpcC797KizXQ4oAHh' +
'VdXJJ81F7j6kwUynPHlXDPdFB2fRj+KVK0KvT2rbp3uKYryJU11Cke8qqMuOoioeeJ1MPDYxM36m1cNSq4GdFx58RAWvbx8TrXnK4IgR16Em5G' +
'K4iqHi5GHHxLgcSDn97WgZPoND+GGZRpPYH85cgiiRQl1ltXxmFFQ5PuopP8TrW5ZyRcWp7AbmkeZefg5+N6PPnbRJdpw/YlfB0vQiPQZwVdZN' +
'tFZEVK6D1VTnccJlXzuqTjvOZiq6Rhj2KqLSJsofOHgIl8+t0/qsfDioxmSUWGjrRFzhYi/5Oynrdl3KXHIZDXtF6hil8R6I9FBV/RvDLnXKxS' +
'bAdVYhNeINXBMwmXWCTQGG2Y+Jj+dFrfEmiMAtmeowpo9ojTvkD+A/L1UJUMmiVfkuz6WTyZhFRJAgP33j3bsM5k/Fng68UP21hYJyyxZwLWuS' +
'2cKMfUSm3rhD0g4E2g197fwMZ+Bgt8rNe2iP2BhL5dgfFzrx8AfECEDdx45a0AAAAASUVORK5CYII=';

let buff = new Buffer(data, 'base64');
fs.writeFileSync('stack-abuse-logo-out.png', buff);

console.log('Base64 image data converted to file: stack-abuse-logo-out.png');

Aquí puede ver que comenzamos con los datos Base64 (que también podrían haber sido recibidos desde un socket o alguna otra línea de comunicación) y los cargamos en un objeto Buffer. Al crear el búfer, le decimos que está en formato base64, lo que permite que el búfer lo analice en consecuencia para el almacenamiento interno.

Para volver a guardar los datos en su formato PNG sin formato, simplemente pasamos el objeto Buffer a nuestro método fs.writeFileSync y hace la conversión por nosotros.

Conclusión

La codificación Base64 es una de las formas más comunes de convertir datos binarios en texto ASCII sin formato. Es un formato muy útil para la comunicación entre uno o más sistemas que no pueden manejar fácilmente datos binarios, como imágenes en marcado HTML o solicitudes web.

En Node.js, el objeto Buffer se puede usar para codificar y decodificar cadenas Base64 hacia y desde muchos otros formatos, lo que le permite convertir fácilmente datos de un lado a otro según sea necesario.

¿Para qué suele utilizar el formato Base64 en Node.js? ¡Cuéntanos en los comentarios!