Resumen: Este artículo te enseñará a realizar un seguimiento de las acciones de los usuarios entre tu dominio y las cachés de AMP.
Te damos la bienvenida a la última publicación de nuestra serie de artículos sobre AMP Camp, la herramienta de prueba que muestra cómo crear un sitio interactivo con AMP. En esta serie, analizaremos las técnicas y herramientas que utilizamos para crearla, así como las prácticas recomendadas que desarrollamos. Si te interesa crear un sitio interactivo con AMP, ¡esperamos que aprendas algo!
En la publicación anterior, hablamos de cómo usar plantillas tanto en el entorno cliente como en tu servidor. En este artículo, analizaremos las prácticas recomendadas para realizar un seguimiento de los estados de los usuarios entre tu entorno de origen y las cachés de AMP.

Estados de los usuarios y cachés de AMP

Si un usuario visita tu sitio en una caché de AMP y otra vez en tu propio dominio, es importante reconocer que ambos visitantes son la misma persona. Esto puede resultar un poco difícil. Por suerte, existe una solución.
Imagina que diriges BestClips, un sitio que vende los sujetapapeles más eficaces del mundo. Cada sujetapapeles puede contener hasta 50 hojas, y están completamente hechos de soja 100% biodegradable.
Como quieres que los usuarios vean tus artículos lo más rápido posible, compilaste tus páginas de productos con AMP. Entregas páginas AMP desde tu dominio, bestclips.com. Y, cuando las arañas web como las de Google y Bing las descubren, esas páginas AMP se almacenan en cachés AMP. Por lo tanto, cuando un usuario descubra la página de tu producto en Google o en Bing Search, la verá en un iframe de un sitio como google.com o bing.com, y la página se entregará desde una caché AMP, como cdn.ampproject.org o bing-amp.com. Hasta aquí, todo se ve bien.
¿Pero qué ocurre si un usuario descubre tu página en una caché de AMP, agrega sujetapapeles a su carrito y más tarde visita de nuevo tu sitio desde bestclips.com? ¿El carrito seguirá teniendo esos productos? ¿O estará vacío?
(Si tu sitio utiliza un intercambio firmado, muchos navegadores mostrarán tu dominio de origen, incluso si se entrega tu página desde una caché. En ese caso, el problema desaparece. De lo contrario, es bueno saber cómo resolverlo).

¿Cuál es el inconveniente?

Las cachés de AMP ayudan a que tus páginas web sean rápidas al mismo tiempo que preservan la privacidad de los usuarios. Sin embargo, una caché también introduce un nivel de complejidad adicional: los usuarios pueden acceder al sitio no solo en tu dominio, sino también en el dominio de la caché.
Supongamos que bestclips.com, siguiendo la práctica estándar de la Web, realiza un seguimiento del estado de un usuario mediante una cookie que contiene un ID de sesión. Luego, cada vez que el usuario visita páginas de bestclips.com, tu servidor recupera la cookie, lee el ID de la sesión y restablece el estado del usuario a partir de los datos almacenados en tu servidor que están asociados con ese ID.
Digamos que el usuario visita la página de tu producto, ve unos sujetapapeles sin los cuales no puede vivir y quiere agregarlos al carrito. Hace clic en un botón, y el sitio envía datos a tu servidor:
<form action-xhr="/add-to-cart" method="POST">
Si el usuario está en tu entorno de origen, la solicitud incluirá una cookie de sesión. En parte, esa solicitud se vería así:
POST /add-to-cart HTTP/2.0 Cookie: session_id=12345
Sin embargo, si el usuario visita el sitio en una caché de AMP, esa solicitud a tu servidor podría en realidad provenir de ampproject.org o bing-amp.com, un dominio diferente. El navegador asocia tu cookie con bestclips.com y, por lo tanto, ahora es una cookie de terceros. La mayoría de los navegadores las enviarán sin problemas. No obstante, es posible que los usuarios hayan configurado sus navegadores para que bloqueen las cookies de terceros. Y algunos navegadores simplemente bloquearán una cookie de terceros bajo ciertas circunstancias. Eso haría que tu solicitud se viera así, sin un encabezado de cookie:
POST /add-to-cart HTTP/2.0
¿Qué se puede hacer?

La solución, en resumen

(Para simplificar, de ahora en adelante, usaremos el término "entorno de origen" para referirnos a tu dominio, y "caché" para hacer referencia a una caché de AMP).
La solución es doble. En tu dominio, identifica a los usuarios con una cookie de sesión, como siempre. En la caché y en un navegador que acepte cookies de terceros, haz lo mismo. De lo contrario, cada vez que un usuario realice una acción que modifique el estado de la aplicación, redirecciónalo inmediatamente a tu entorno de origen, donde podrá usar o crear una cookie almacenada en tu dominio y luego realizar el cambio deseado.
En otras palabras, si el usuario quiere agregar sujetapapeles al carrito, y si no puedes leer su cookie, ¡no te asustes! Simplemente, redirecciónalo a tu entorno de origen, donde podrá cambiar el contenido del carrito a su gusto.
Este redireccionamiento es posible gracias a un encabezado HTTP específico de AMP llamado AMP-Redirect-To. Si una página de AMP realiza una solicitud al servidor usando <amp-form>, y la respuesta del servidor contiene este encabezado, AMP redireccionará a la página deseada.
Este es el flujo entero:
  1. El usuario navega a la página del producto. Si el usuario está en el entorno de origen, este establece una cookie de sesión (si no está presente).
  2. El usuario realiza una acción para cambiar lo que hay en el carrito.
  3. El navegador envía datos sobre el cambio del entorno de origen mediante POST XHR.
  4. El entorno de origen comprueba si la solicitud no contenía ninguna cookie de sesión y procedía de la caché.
    • Si eso es verdadero:
      1. La respuesta le dice a AMP que redireccione a una URL del entorno de origen que incluya una string de búsqueda que describa el cambio del usuario.
      2. Cuando el origen ve esa string de búsqueda, lee o crea la cookie, hace el cambio y redirecciona de nuevo a una URL del entorno de origen que no incluye esa molesta string de búsqueda.
    • Si ese no es el caso, entonces podemos simplemente recuperar la sesión del usuario y hacer el cambio correspondiente. O estamos en el entorno de origen o estamos en la caché con un navegador que permite cookies de terceros.
Ya sea que el usuario comience en la caché o en el entorno de origen, al final de este proceso, tiene una sesión y sus cambios se reflejan en el servidor.

La solución, en detalle

Describamos este proceso paso por paso. Supongamos que un usuario visita nuestra página de productos y decide comprar uno de nuestros nuevos superclips. La página de nuestro producto es https://bestclips.com/product, pero el usuario podría acceder a ella en nuestro entorno de origen o en una caché de AMP.
Paso 1. El usuario llega a nuestra página de productos. Esta página contiene un formulario que permite al usuario seleccionar una cantidad, así como un botón de envío que le permite agregar el producto al carrito. Esto se vería así:
<form action-xhr="/api/add-to-cart" method="POST" <select name="quantity"> <option value="0">0</option> <option value="1" selected>1</option> <option value="2">2</option> </select> <input type="submit" value="Add to Cart"> </form>
Paso 2. Supongamos que el usuario deja la cantidad en "1" y presiona "Agregar al carrito".
Paso 3. Se envía el formulario, y AMP envía una solicitud POST XHR a nuestro servidor, bestclips.com. (Para garantizar que esa solicitud funcione incluso desde una caché, es necesario configurar encabezados CORS. Si estás usando un nodo, puedes simplemente conectar el middleware CORS de AMP). En el entorno de origen, la solicitud se ve así:
POST /api/add-to-cart HTTP/2.0 AMP-Same-Origin: true Cookie: session_id=12345 quantity=2
Ten en cuenta que AMP agrega convenientemente el encabezado AMP-Same-Origin cuando se está ejecutando en el entorno de origen.
Si el usuario está en la caché con un navegador que permite cookies de terceros, la solicitud se verá así:
POST /api/add-to-cart HTTP/2.0 Cookie: session_id=12345 quantity=2
Si el usuario está en una cache con un navegador que bloquea las cookies de terceros, también faltara el encabezado de cookie:
POST /api/add-to-cart HTTP/2.0 quantity=2
Paso 4. Esta es la parte divertida.
El servidor comprueba si la solicitud carece de una cookie de sesión y si provino de la caché. Si no hay ninguna cookie, entonces el navegador no permitió que se estableciera una. Eso también podría suceder si el navegador del usuario bloqueara todas las cookies; en ese caso, redireccionar al entorno de origen no sería útil. No podríamos realizar un seguimiento de los estados de los usuarios con cookies. Por eso, también comprobamos si la solicitud provino de la caché, porque es el caso que podemos resolver.
Si la solicitud carece de una cookie de sesión y proviene de la caché, carecerá tanto del encabezado de cookie como del encabezado AMP-Same-Origin, como se muestra arriba. El servidor detecta esta condición:
if (!request.cookies.session_id && request.headers['amp-same-origin'] !== 'true')
Si ese es el caso, el servidor envía una respuesta que le indica a AMP que redireccione a una URL del entorno de origen. En esa URL, incluye una string de búsqueda que describe el cambio del usuario, de esta forma:
response.setHeader("AMP-Redirect-To", `https://bestclips.com?item=${request.body.itemName}&quantity=${request.body.quantity}`);
Esto envía una respuesta que contiene un encabezado como el siguiente:
AMP-Redirect-To:https://bestclips.com/product?item=superclip&quantity=1
Cuando esta respuesta regresa al navegador, AMP nota el encabezado y redirecciona a https://bestclips.com/product?item=superclip&quantity=1. Esta solicitud lleva a bestclips.com, ¡nuestro entorno de origen! El servidor de origen puede leer la cookie de sesión o, si esta no existe, crear una. Agrega un superclip al carrito del usuario. Luego, redirecciona a https://bestclips.com/product
En otras palabras, redirecciona de nuevo a la página del producto sin la string de búsqueda. De esa manera, el usuario no experimentará dificultades que podrían deberse a la string de búsqueda. (Consulta "Así es como no se hace" más abajo).
Como se prometió, ahora el usuario tiene una cookie de sesión y se realizó el cambio en el servidor.

¿Puedo usar un ID de cliente?

Si has trabajado con AMP, sabrás que existe el ID de cliente, que permite a los paquetes de análisis hacer un seguimiento del trayecto de un usuario desde la caché hasta el entorno de origen. En el entorno de origen, se almacena en una cookie y persiste durante un año. En la caché, también se almacena en una cookie, y si no está allí, se puede crear con una llamada a la API de ID de cliente. Por lo tanto, sería tentador utilizar esto para identificar sistemáticamente a un usuario.
Por desgracia, aunque los sitios utilizan esta solución, tiene algunos problemas. El ID de cliente identifica a un único usuario para ciertos trayectos entre los entornos de origen y las cachés, pero no en todos los casos. Además, su comportamiento entre sitios puede ser bloqueado por los mismos navegadores con los que hemos estado tratando en este artículo.
AMP Linker hace que esos trayectos entre sitios sean más confiables, ya que preserva el ID de cliente como un parámetro de la string de búsqueda. Esto proporciona otra forma de usar el ID de cliente. Sin embargo, significa que el identificador único del usuario será visible en su URL. Las URL tienden a registrarse en los servidores y, en ocasiones, personas malintencionadas descubren los archivos de registro. En el peor de los casos, el usuario podría compartir su URL públicamente y así exponer su identificador a todo el mundo. De cualquier forma, su sesión es vulnerable a cualquier intento de hackeo. Por eso, en los ejemplos anteriores, usamos POST en lugar de GET.

¿Realmente necesito hacer esto?

Puedes no hacerlo. Sin embargo, como los navegadores bloquean las cookies de terceros con mayor frecuencia, esta solución será cada vez más esencial para que los usuarios puedan utilizar tu sitio sin problemas en tus cachés de AMP y entornos de origen. Y, si explicar el flujo de arriba lleva un tiempo, no es difícil de implementar.

¿En serio?

Mira cómo lo hicimos en el sitio de demostración de AMP Camp. Este es el código del servidor. Y este es el formulario de la página de productos. La única diferencia es que, en este sitio de demostración, cuando el usuario agrega un artículo a su carrito, lo redireccionamos a la página de detalles del carrito.
Escrito por Ben Morss, representante de desarrolladores