Saltar al contenido

El objeto Astro en SSR

Bajo demanda, cada página recibe algo que en estático no existe de verdad: la petición. El objeto global `Astro` se puebla con la realidad del instante —`Astro.request`, `Astro.url`, cookies, cabeceras y `Astro.clientAddress`—. Cómo leer la petición entrante, gestionar cookies y la respuesta, y qué miembros solo tienen sentido con un servidor vivo.

La petición como objeto: Astro.request y Astro.url

En el corazón del renderizado bajo demanda hay un objeto estándar de la plataforma web: Astro.request es un Request, el mismo que usan los Service Workers, Deno y los runtimes del edge. No es una invención de Astro, y eso importa: lo que aprendes aquí es transferible. De él sacas el método, el cuerpo y, sobre todo, las cabeceras que el cliente mandó.

Junto a él, Astro.url es un objeto URL ya parseado con la dirección concreta que se pidió. Su miembro más jugoso es searchParams, la cadena de búsqueda: el trozo de la URL que solo existe petición a petición, porque cada visitante escribe la suya.

ASTRO
---export const prerender = false;const pagina = Number(Astro.url.searchParams.get('pagina') ?? '1');const metodo = Astro.request.method;const acepta = Astro.request.headers.get('accept-language');---<p>Sirviendo la pagina {pagina} para un cliente que prefiere {acepta}</p>

Detente en searchParams: en una página horneada estaría siempre vacío, porque en el build no hay una consulta concreta que leer. Bajo demanda, en cambio, contiene lo que el visitante puso tras el interrogante, y con ello construyes búsquedas, filtros, paginaciones y cualquier vista que dependa de lo que pide cada uno. Es la puerta más común por la que una página deja de ser un documento y se vuelve receptiva.

El método y el cuerpo abren la otra mitad del abanico. Una página o un endpoint bajo demanda pueden mirar Astro.request.method para distinguir una lectura de una escritura, y leer el cuerpo enviado con Astro.request.formData o con el parseo de JSON de la propia plataforma. Ahí es donde una URL deja de solo mostrar y empieza a recibir: un formulario que se procesa, un dato que se guarda.

ASTRO
---export const prerender = false;if (Astro.request.method === 'POST') {  const datos = await Astro.request.formData();  const correo = datos.get('correo');  await suscribir(correo);}---<form method="POST"><input name="correo" type="email" /></form>

Astro tiene además las actions para esto con tipos y validación, pero por debajo todo se apoya en el mismo Request estándar que estás leyendo aquí. Reconocerlo te da una brújula: cuando dudes de qué API usar para leer la petición, la respuesta casi siempre es “la de la plataforma web”, porque es sobre ella que Astro construye.

Cookies, cabeceras y la dirección del cliente

Las cookies tienen su propia API tipada en Astro.cookies, con métodos para leer, escribir, comprobar y borrar. Leer una cookie te da el estado que el navegador arrastra entre visitas —una sesión, una preferencia—; escribirla, junto con ajustar la respuesta saliente, es como devuelves ese estado actualizado.

ASTRO
---export const prerender = false;const sesion = Astro.cookies.get('sesion')?.value;const usuario = sesion ? await validarSesion(sesion) : null;if (!usuario) {  Astro.response.status = 401;}Astro.cookies.set('ultima_visita', new Date().toISOString(), {  path: '/',  httpOnly: true,  secure: true,  sameSite: 'lax',});---

Fíjate en las opciones al escribir la cookie: no son adorno. httpOnly la oculta a JavaScript del cliente y frena el robo por scripts inyectados; secure la limita a HTTPS; sameSite acota cuándo se envía entre sitios y mitiga el CSRF. Una cookie de sesión sin estas banderas es un agujero de seguridad, y como se fijan en el servidor, solo existen de verdad bajo demanda. Aquí aparecen además dos miembros más del objeto: Astro.response te deja fijar el estado y las cabeceras salientes —un 401 para el no autenticado, una redirección, una cabecera de caché—, y Astro.clientAddress te entrega la dirección IP desde la que llega la petición, útil para geolocalización aproximada, límites de tasa o registro.

Lo que solo existe bajo demanda

El objeto Astro es siempre el mismo símbolo, pero no todos sus miembros están habitados en los dos momentos de render. Los que describen la petición solo cobran sentido cuando hay una. Estos son los que solo cobran vida bajo demanda:

  • Astro.url.searchParams, con lo que el visitante escribe tras el interrogante.
  • Astro.request.headers y Astro.request.method, lo que envió el navegador.
  • Astro.cookies, el estado que el cliente arrastra entre visitas.
  • Astro.clientAddress y Astro.locals, la IP y lo que dejó el middleware.

En una página prerenderizada, Astro.request.headers viene esencialmente vacío, Astro.url.searchParams no contiene nada, las cookies no se pueden leer con fiabilidad, y Astro.clientAddress no se limita a devolver vacío: lanza un error, porque no existe ninguna dirección de cliente en el build.

Hay una consecuencia menos obvia de leer la petición: la respuesta deja de poder compartirse a ciegas. Una página horneada es idéntica para todos y una CDN puede repartirla sin más; una página que depende de una cookie o de una cabecera produce una respuesta distinta por visitante, y cachearla sin cuidado serviría los datos de uno a otro. Por eso, en cuanto tu página se personaliza, la caché deja de ser automática y pasa a exigir cabeceras deliberadas —o directamente ninguna caché compartida—. El objeto Astro poblado es cómodo, pero cada miembro de petición que lees ata la respuesta a un visitante concreto, y esa atadura es justo lo que hay que respetar al decidir qué se guarda y qué no.

Esa asimetría entre los dos momentos no es un defecto, sino la definición misma de lo que significa cada modo. El estático es una página escrita antes de conocer a su lector; el bajo demanda es una página escrita en el acto para el lector que acaba de llegar. El objeto Astro refleja esa diferencia con precisión: sus miembros de petición están vivos exactamente cuando hay alguien preguntando, y en blanco cuando la página se compuso en la soledad del build.

Este es también el motivo por el que no puedes “probar” SSR con solo leer la petición en una página estática y esperar que funcione: el objeto está ahí, pero sus miembros de petición no tienen nada que reflejar hasta que la página corre bajo demanda. La forma correcta de despertar el objeto Astro es declarar la página dinámica con export const prerender = false; entonces, y solo entonces, la petición existe y sus miembros se llenan.