Blog ·
Una insignia que ponía una cookie en cada página
Una imagen del pie de página costaba veintidós puntos de Lighthouse en todo el sitio. El arreglo no fue quitarla, y lo interesante es qué rechaza un proxy.
Por Provibr
La puntuación de prácticas recomendadas de nuestro sitio de marketing era 78 en todas las páginas. No en una página: en todas, la portada, la de precios, la documentación, todo, de forma uniforme. Las puntuaciones uniformes son buena señal, porque significan que la causa está en algo que comparten todas las páginas.
Era una sola etiqueta de imagen en el pie. Una insignia de listado de lanzamiento, cargada directamente desde la plataforma que la emite, porque así es como se supone que se incrusta una insignia así y porque el número que lleva se supone que está vivo.
Lo que puede hacer una etiqueta de imagen
La insignia se sirve desde un host de API que está detrás de Cloudflare, y Cloudflare responde a las peticiones con su cookie de gestión de bots: __cf_bm, SameSite=None, Secure, con alcance en el dominio de quien emite la insignia. Eso no es una decisión del sitio de quien es la insignia. Es lo que hace una CDN, sobre un SVG, en cada carga de página, para cada visitante.
Dos auditorías de Lighthouse reaccionan a eso. La auditoría de cookies de terceros pesa cinco de los veintiocho pesos de la categoría, y una incidencia del inspector pesa uno. Seis pesos perdidos en una imagen. A lo largo de las treinta y ocho mediciones de la ronda anterior, esa era toda la distancia entre 78 y 100.
La tercera consecuencia es la que no captura ninguna puntuación. La dirección IP de cada visitante iba a una empresa con la que no había elegido hablar, en cada página, a cambio de un número en un pie.
Quitarla tampoco es la respuesta
Ya habíamos dejado escrito el compromiso, en un comentario, meses antes: si alguna vez se quiere esto sin banner de consentimiento, alojar el SVG uno mismo es la vía. Con el contraargumento adjunto, que es que una copia alojada por uno mismo es una fotografía. La insignia existe para mostrar un listado vivo; congele los bytes y tendrá una foto de un listado.
Hay una tercera vía, y solo resulta evidente una vez que se separan dos cosas que el navegador hace a la vez. El navegador está trayendo bytes, y el navegador está haciendo una conexión. Solo la segunda es el problema.
Así que la insignia viene ahora de nuestro propio origen, en una ruta de nuestra propia API, y esa ruta trae el recurso de arriba en el servidor. Los mismos bytes. El navegador del visitante hace una petición, a nosotros. No hay nada en el cable sobre lo que poner una cookie, porque no hay ningún tercero en la página del visitante en absoluto. Y el número sigue vivo, porque seguimos preguntando.
Las prácticas recomendadas pasaron de 78 a 100 en treinta y dos de treinta y seis mediciones. Las cuatro restantes son las páginas de artículo, que se quedan en 96 por un botón de tercero completamente distinto, y eso es una decisión aparte y no un resto.
Lo que un proxy le debe a aquel para quien hace de proxy
Servir los bytes de otro desde el propio origen cambia lo que son. Un SVG cargado por una etiqueta de imagen no puede ejecutar script; esa es una garantía de la especificación y es buena. Pero en cuanto esos bytes salen de nuestro dominio, lo que hay dentro es nuestro.
Así que la ruta comprueba la respuesta antes de pasarla. Esa comprobación no es, a propósito, un saneador. Un saneador intenta volver seguro un contenido peligroso; esta rechaza cualquier cosa que no se parezca a la insignia que ya conocemos, y la ruta recurre a una copia congelada. El peor caso es una insignia de esta mañana en lugar de una insignia de este minuto, que es un precio que vale la pena pagar por no tener que razonar nunca sobre lo que podría contener la respuesta de otro.
Dos de los rechazos van específicamente sobre aquello para lo que existía todo este cambio. Un SVG puede referenciar una imagen externa, y puede referenciar un recurso externo desde una declaración de estilo. Cualquiera de las dos alcanzaría a un tercero una capa más adentro que la etiqueta que acabábamos de quitar, desde dentro de un fichero que servimos como propio. Una comprobación que solo buscara scripts habría dejado pasar las dos.
Fallar a una foto, a propósito
Todos los caminos de fallo devuelven la copia congelada con estado 200. Error de red, tiempo agotado, un estado que no es 200, un cuerpo del que la comprobación no se fía: todos, 200, con una insignia dentro.
El razonamiento va sobre cómo se ve el fallo. Un 404 o un 502 en una imagen del pie de todas las páginas es un icono de imagen rota en todas las páginas, lo que se lee como un sitio roto, por un elemento decorativo. Una insignia un poco vieja no se lee como nada.
La compensación es que el camino de fallo lleva una cabecera de caché corta mientras que el camino de éxito lleva una larga. Si no, una caída de cinco minutos arriba clavaría la copia congelada delante de todo el mundo durante toda la ventana de caché.
Hay una sola copia congelada y a propósito no vive como fichero en el directorio público. Como fichero tendría una segunda dirección pública junto a la ruta, y una ronda futura podría razonablemente soltar una etiqueta de imagen apuntando directa a ella, lo que quita en silencio el comportamiento vivo que este arreglo entero existe para conservar. Guardada como constante, la única manera de servirla es a través de la ruta que además prueba primero la red.
Dos cachés, con trabajos distintos
Aquí hay dos capas de caché y confundirlas produce un sistema que o machaca al origen de arriba o muestra bytes rancios para siempre.
La caché de datos del framework guarda la respuesta de arriba: con una revalidación de seis horas, un visitante cada seis horas provoca una petición saliente, sea cual sea el tráfico. La cabecera de caché HTTP guarda nuestra respuesta, en la CDN y en el navegador. El de arriba pone cuatro horas en su propia respuesta; seis por nuestro lado es un medio paso más ancho a propósito, para que una caída allí no nos deje caer sobre la copia congelada a un ritmo de cuatro horas.
Una trampa pequeña, que costó una compilación. Next lee la configuración de segmento de ruta estáticamente del código fuente, así que la exportación de revalidación tiene que ser un número literal. Escribirla como una expresión, aunque sea como una constante declarada unas líneas más abajo en el mismo fichero, aborta la compilación con un error de configuración de segmento inválida. La constante lee ahora desde la exportación y no al revés, así que sigue habiendo exactamente un número.
El 307 que era una bandera de arranque
La misma ronda dedicó tiempo a algo que parecía un fallo de enrutado y no lo era, y merece la pena dejarlo escrito porque desperdició una ronda anterior entera.
Al ejecutar la compilación de producción en local, toda ruta de marketing sin prefijo respondía 307, redirigiendo a sí misma. No las rutas localizadas, no las rutas de API: las que no llevan prefijo. Esto había bloqueado la mitad inglesa de todos los barridos locales de disposición durante semanas y estaba anotado como un defecto sin explicar.
Es la vinculación al host. Arrancado con una dirección de bucle local literal como nombre de host, Next deja ese valor tal cual, mientras que un nombre de host vacío o comodín se normaliza a localhost. La URL inicial y el origen que calcula el middleware discrepan entonces, la reescritura se queda absoluta, el router la trata como externa y vuelve a entrar. Arrancado con el comodín, que es el valor que usa producción, o con localhost, todo responde 200.
No había nada que reparar. Lo que había que hacer era escribir la línea de arranque correcta en el script, y escribir por qué, porque, si no, un defecto que en realidad es una bandera lo volverá a descubrir la persona siguiente con la misma confianza.
El fallo que elegimos no arreglar
Una tercera cosa de la misma ronda es una no reparación deliberada, y esas merecen escribirse al menos con tanto cuidado como los arreglos.
Habíamos visto 404 de fragmentos en el campo: HTML que referencia ficheros JavaScript que ya no existen. La explicación resultó ser una cabecera. La portada lleva una ventana de stale-while-revalidate medida en un año, así que a un borde de la CDN se le permite servir HTML de una compilación más vieja durante muchísimo tiempo, y los nombres de fragmento de ese HTML pertenecen a esa compilación.
El mando está ahí mismo y lo dejamos en paz, porque esa misma copia rancia es lo que mantuvo el sitio respondiendo durante un bucle de caídas de la base de datos quince días antes. Acortar la ventana cambia una carga rota poco frecuente por una caída total aún menos frecuente. Eso es un compromiso real, pertenece a quien tenga el riesgo, y el trabajo de la ronda era explicar el mecanismo y no tomar la decisión.
Lo que dejaríamos por escrito
- Una puntuación uniforme en todas las páginas apunta a algo que comparten todas las páginas. Es la pista más barata que va a conseguir.
- Una etiqueta de imagen es una conexión, no solo bytes. Todo lo que una CDN quiere hacer en una petición, lo hace también en esa.
- Alojar uno mismo no es la única alternativa a incrustar. Traer el recurso en el servidor conserva el comportamiento vivo y quita al tercero de la página del visitante.
- En cuanto sirve los bytes de otro, son suyos. Compruébelos, y compruebe específicamente las referencias que reabrirían el agujero que acaba de cerrar.
- Prefiera una foto rancia a una imagen rota. Para lo decorativo, un fallo visible cuesta más que una obsolescencia invisible, siempre que la ventana rancia sea corta en el camino de fallo.
- No le dé una dirección pública a la copia congelada. Todo lo alcanzable acabará enlazado, y el camino vivo quedará sorteado en silencio.
- Sepa qué guarda cada caché. Una guarda la respuesta de arriba, otra la suya, y sus ventanas responden a preguntas distintas.
- Algo rojo es a veces una bandera y no un fallo. Reproduzca el mecanismo antes de reparar el síntoma y, si resulta ser su propia orden de arranque, dígalo en el script.
Para que quede claro qué es esto: la ruta está en producción y las puntuaciones vienen de una compilación de producción local sobre treinta y seis mediciones, no de datos de campo. La explicación de los 404 de fragmentos se deriva de cabeceras y no se ha reproducido, y la decisión sobre esa ventana de caché pertenece a quien carga con el riesgo de disponibilidad, no a la ronda.
Del trabajo de plataforma en Provibr. Otra medición que salió verde por el motivo equivocado está en una excepción de accesibilidad que se mide sola, y un campo que guardaba una intención donde correspondía un hecho está en una fecha futura no es un calendario.