En un post anterior explicábamos qué son las cookies, como funcionan y hacíamos un repaso de todos sus parámetros y características. Si no leíste ese tutorial, te recomiendo hacerlo antes de seguir o puede que no entiendas algunas de las cosas que trataremos aquí, en especial la sintaxis y detalles de cada parámetro. Hoy nos vamos a centrar en el uso de cookies en JavaScript y le dedicaremos poco a ese apartado.

Repaso rápido

Una cookie es un string (cadena de texto) que contiene parejas parametro=valor separadas por ; de la siguiente forma:

<nombre>=<valor>; expires=<fecha>; max-age=<segundos>; path=<ruta>; domain=<dominio>; secure; httponly;

Los parámetros son:

<nombre>=<valor>
Requerido. <nombre> es el nombre (key) que identifica la cookie y <valor> es su valor. A diferencia de las cookies en PHP, en JavaScript se puede crear una cookie con un valor vacío (<nombre>=).
expires=<fecha> y max-age=<segundos>
Opcional. Ambos parámetros especifican el tiempo de validez de la cookie. expires establece una fecha (ha de estar en formato UTC) mientras que max-age establece una duración máxima en segundos. max-age toma preferencia sobre expires. Si no se especifica ninguno de los dos se creará una session cookie. Si es max-age=0 o expires=fecha-pasada la cookie se elimina.
path=<ruta>
Opcional. Establece la ruta para la cuál la cookie es válida. Si no se especifica ningún valor, la cookie será válida para la ruta la página actual.
domain=<dominio>
Opcional. Dentro del dominio actual, subdominio para el que la cookie es válida. El valor predeterminado es el subdominio actual. Establecer domain=.miweb.com para una cookie que sea válida para cualqueir subdominio (nota el punto delante del nombre del dominio). Por motivos de seguridad, los navegadores no permiten crear cookies para dominios diferentes al que crea la cookie (same-origin policy).
secure
Opcional. Parámetro sin valor. Si está presente la cookie sólo es válida para conexiones encriptadas (por ejemplo mediante protocolo HTTPS).
HttpOnly
Opcional. Parámetro no disponible en JavaScript ya que crea cookies válidas sólo para protocolo HTTP/HTTPS y no para otras APIs, incluyendo JavaScript.

La propiedad document.cookie

La propiedad document.cookie es todo lo que se necesita para trabajar con cookies client-side desde JavaScript. A través de ella podemos crear, leer, modificar y eliminar cookies. Veamos cada uno de los casos.

1

Crear cookies

Establecer una cookie en JavaScript es tan fácil como crear el string que define la cookie y asignarlo a document.cookie. Por ejemplo:

document.cookie = "nombrecookie=valorcookie; max-age=3600; path=/";

Si queremos crear varias cookies, tenemos que hacer este paso una vez para cada una. Por ejemplo, con el siguiente código se crearían las cookies comida_favorita y color_favorito:

document.cookie = "comida_favorita=arroz; max-age=3600; path=/";
document.cookie = "color_favorito=amarillo";

Este comportamiento se debe a que document.cookie no es un dato con un valor (data property), sino una propiedad de acceso con métodos set y get nativos (accessor property). Cada vez que se le asigna una nueva cookie, no se sobrescriben las cookies anteriores sino que la nueva se añade a la colección de cookies del documento.

Recuerda que las cookies se envían en las cabeceras HTTP y, por tanto, deben estar correctamente codificadas. Puedes utilizar encodeURIComponent(), acostúmbrate a utilizarlo siempre para evitarte sorpresas:

var testvalue = "Hola mundo!";
document.cookie = "testcookie=" + encodeURIComponent( testvalue );

Si vas a utilizar el parámetro expires, recuerda que ha de ser una fecha en formato UTC. Te puede ser de ayuda el método Date.toUTCString(). Por ejemplo, una cookie con caducidad para el 1 de Febrero del año 2068 a las 11:20:

var expiresdate = new Date(2068, 1, 02, 11, 20);
var cookievalue = "Hola Mundo!";
document.cookie = "testcookie=" + encodeURIComponent( cookievalue ) + "; expires=" + expiresdate.toUTCString();

Recuerda también que si no se específica fecha de caducidad la cookie será válida sólo para la sesión actual.

2

Modificar cookies

En el punto anterior se dijo que cada vez que se asigna una cookie a document.cookie, esta es añadida a la colección de cookies del documento. Esto es verdad excepto si la cookie asignada tiene un identificador que ya existe. En este caso se modifica la cookie existente en lugar de añadir una más.

Por ejemplo, podemos crear la siguiente cookie con identificador nombre y valor Miguel:

document.cookie = "nombre=Miguel";

Si queremos modificar el valor, por ejemplo cambiarlo por Juan:

document.cookie = "nombre=Juan";

Es importante tener en cuenta que si una cookie se crea para un dominio o para un path determinado y se quiere modificar, el dominio y el path han de coincidir. De lo contrario se crearán dos cookies diferentes válidas para cada path y dominio. Por ejemplo, imaginemos que estamos en “miweb.com/blog” (el valor predeterminado del path es en este caso /blog):

// Supongamos que estamos en "miweb.com/blog"
// y creamos las siguientes cookies

// Creamos la cookie para el path "/"
document.cookie = "nombre=Miguel; path=/";

// Con la siguiente linea se crea una nueva cookie para el path "/blog" (valor por defecto)
// pero no se modifica la cookie "nombre" anterior porque era para un path diferente
document.cookie = "nombre=Juan";

// Con la siguiente línea SI se modifica la cookie "nombre" del path "/" correctamente
document.cookie = "nombre=Juan; path=/";
3

Eliminar cookies

Para eliminar una cookie desde JavaScript se debe asignar una fecha de caducidad (expires) pasada o un max-age igual a cero. En ambos casos da igual el valor que se le asigne a la cookie porque se eliminará pero ha de darse el nombre de la cookie aunque sea sin valor.

Por ejemplo, creamos la cookie con el identificador nombre y valor Miguel igual que antes:

document.cookie = "nombre=Miguel";

Si queremos eliminarla:

document.cookie = "nombre=; expires=Thu, 01 Jan 1970 00:00:00 UTC";

// O con max-age
document.cookie = "nombre=; max-age=0";

Al igual que ocurría con la modificación de cookies, para la eliminación el path y el dominio también tienen que coincidir:

// Se crean dos cookies con el mismo identificador
// para dos paths diferentes
document.cookie = "nombre=Miguel; path=/noticias";
document.cookie = "nombre=Juan; path=/blog";

// Solo se elimina la cookie del path /noticias
document.cookie = "nombre=; max-age=0; path=/noticias";
4

Leer y obtener el valor de las cookies

Puede que obtener el valor sea el paso más tedioso de trabajar con cookies en JavaScript, y es que no hay un método de lectura directo para cada cookie individual. Sólo se puede obtener un string con todas las cookies válidas para el documento y manipular el string hasta encontrar el nombre y valor de la cookie que queremos.

El string con todas las cookies se obtiene del siguiente modo:

var lasCookies = document.cookie;

Y tiene el siguiente formato:

"cookie1=valor1;cookie2=valor2;cookie3=valor3[;...]"

Quiero remarcar los siguientes aspectos:

  1. El string sólo contiene pares de nombre de la cookie y su valor. No se puede acceder a otros parámetros a través de document.cookie.
  2. Sólo se obtienen las cookies válidas para el documento actual. Esto implica que cookies para otros paths, dominios o cookies caducadas no se pueden leer. Aunque en una página puedan crearse cookies para otros subdominios y paths, sólo se pueden leer las que san válidas para el subdominio y path actual.

Por ejemplo, imagina que estamos en la subdominio noticias.miweb.com. Aquí podemos crear una cookie para el subdominio tienda.miweb.com, pero esta cookie no es válida para el documento en el que estamos (noticias.miweb.com), por lo que no podemos leer su valor desde aquí, aunque sí hemos podido crearla:

// Suponiendo que estamos en noticias.miweb.com

// Se crean dos cookies para dos subdominios diferentes
document.cookie = "cookienoticias=valorcn; domain=noticias.miweb.com";
document.cookie = "cookietienda=valorct; domain=tienda.miweb.com";

var lasCookies = document.cookie;
alert( lasCookies );
// Obtendremos cookienoticias=valorcn
// No podemos acceder a la cookie cookietienda
// porque es válida solo para tienda.miweb.com y estamos en noticias.miweb.com

Ahora que sabemos cómo obtener las cookies, ¿cómo leemos los valores de cookies individuales? Pues tenemos que manipular el string con todas las cookies y dividirlo por cada ; para separar cada par nombrecookie=valor. Luego se divide cada uno de estos pares por = para separar el nombre de la cookie y su valor. Se puede conseguir utilizando varios métodos, a continuación algunos de los más comunes:

Ejemplo con split

// Adapatado de http://www.quirksmode.org/js/cookies.html#script
function readCookie(name) {

  var nameEQ = name + "="; 
  var ca = document.cookie.split(';');

  for(var i=0;i < ca.length;i++) {

    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) {
      return decodeURIComponent( c.substring(nameEQ.length,c.length) );
    }

  }

  return null;

}

// Creamos una cookie
document.cookie = "pais=" + encodeURIComponent( "Uruguay" );

// Leemos la cookie
var miCookie = readCookie( "pais" );

// Muestra "Uruguay"
alert( miCookie );

Ejemplo con regex

function readCookie(name) {

  return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + name.replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;

}

// Creamos una cookie
document.cookie = "pais=" + encodeURIComponent( "Ecuador" );

// Leemos la cookie
var miCookie = readCookie( "pais" );

// Muestra "Ecuador"
alert( miCookie );

Puedes elegir el que quieras o utilizar alguno de los cientos de snippets que circulan por la red que te harán la vida más fácil. Personalmente me gustan el framework que proponen en MDN y JS Cookie.

Referencias

  • Heiner

    Respetado Ingeniero;

    Le hago la siguiente consulta.

    Requiero borrar o caducar las cookies que residen en mi
    navegador. Estas cookies no son creadas por mí, sino se crean una vez desde mi página
    accedo a otro portal (página web) ingresando claves y password.

    La necesidad de caducarlas, está en que esa web (a la que
    accedo mediante clave) requiere ser accedida por otros usuarios desde el mismo
    navegador y al intentar ingresar con una nueva clave y password, el navegador
    me arroja un mensaje de prohibición de ingreso por no tener permisos para
    ingreso. Esto debido a que la sesión no ha sido borrada, y no se podrá borrar
    dado que desde mi página lo que hago es utilizar los servicios de la web foránea
    mediante una url.

    Espero haberme explicado y quedo muy agradecido por su
    colaboración

  • isaac

    En el post comentas esto:

    Como y se puede utilizar cualquier valor arbitrario que deseemos, sólo hay que tener en cuenta que si contiene espacios o caracteres especiales hay que codificarlos (reemplazarlos por su código ASCII); en JavaScript lo podemos hacer con encodeURIComponent(); en PHP se podría hacer con urlenconde(); al leer el valor habría que descodificarlo con decodeURIComponent() o urldecode().

    Como bien dices como y se puede utilizar cualquier valor arbitrario que deseemos, sólo hay que tener en cuenta que si contiene espacios o caracteres especiales hay que codificarlos.

    Viendo el ejemplo con Split, veo que a la función encodeURIComponent se le pasa como parámetro solo el valor de la cookie. ¿Qué es entonces lo que deberíamos codificar al enviar y descodificar al recibir una cookie solo su valor o también el nombre?

    • Si utilizas esos caracteres en el nombre de la cookie, codifícalo también. Aunque la verdad que nunca he visto a nadie que utilice caracteres no latinos y demás en el nombre de una cookie, sería aumentar la complejidad sin necesidad. Pero por poder, puedes:

      function readCookie(name) {

      var nameEQ = encodeURIComponent( name ) + "=";
      var ca = document.cookie.split(';');

      for(var i=0;i < ca.length;i++) {

      var c = ca[i];
      while (c.charAt(0)==' ') c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) {
      return decodeURIComponent( c.substring(nameEQ.length,c.length) );
      }

      }

      return null;

      }

      document.cookie = encodeURIComponent( "Tu país" ) + "=" + encodeURIComponent( "Uruguay" );
      var miCookie = readCookie( "Tu país" );
      alert( miCookie );

    • isaac

      ok perfecto. Pero poque se le vuelve a pasar otra vez la función encodeURIcomponent dentro de la función readCookie?

      var nameEQ = encodeURIComponent( name ) + “=”;

    • Fíjate que en ese ejemplo utilizando split() requiere conocer la longitud exacta de name. Y la longitud no es igual antes y después de encodeURIComponent(). Por eso, si el nombre de la cookie se creó con encodeURIComponent(), tienes que leerla también pasando el nombre por encodeURIComponent(). Eso no sería necesario en el ejemplo que utiliza un regex ya que no depende en la longitud del nombre.

  • isaac

    hola, sigiendo viendo el articulo he visto creo un error:

    Por ejemplo, imagina que estamos en la subdominio noticias.miweb.com. Aquí podemos crear una cookie para el subdominio tienda.miweb.com pero no podemos leer su valor desde aquí pues la cookie no es válida para el documento en el que estamos.

    me imagino que quisites decir “pues la cookie sólo es válida para el documento en el que estamos” ¿?

    • Está correcto. Si estás en noticias.miweb.com, puedes crear una cookie para tienda.miweb.com, pero NO es válida para el documento en el que estamos (noticias.miweb.com) y por eso no puedes leer su valor estando en noticias.miweb.com. En otras palabras, se pueden crear cookies para otros subdominios, pero no leer cookies de otros subdominios.

    • isaac

      Ah vale vale, ahora si lo entendí. Error mío entonces.