Despliegue del frontend¶
El paso 9 del protocolo, y el mismo para cualquier framework: el frontend y la API se sirven desde el mismo origen.
Frontend y API en el mismo origen¶
La sesión va en una cookie SameSite=Strict, y el navegador solo la envía si el frontend y la API
son el mismo sitio. Que lo sean depende de cómo se despliegan:
| Despliegue | ¿Mismo sitio? | Qué hace falta |
|---|---|---|
Un dominio con rutas (https://app.cliente.com y /api) |
sí, y mismo origen | nada |
| Una IP con puertos distintos (on-premise) | sí, pero distinto origen | CORS con los orígenes exactos |
Dos Web Apps de Azure (app-x.azurewebsites.net y api-x.azurewebsites.net) |
no | el proxy /api |
En Azure, dos Web Apps no son el mismo sitio
azurewebsites.net está en la Public Suffix List, así que para el navegador
app-x.azurewebsites.net y api-x.azurewebsites.net son sitios distintos, como dos dominios
cualquiera. La cookie de la API sería de terceros, y Safari, Firefox en modo estricto y Chrome
en incógnito la bloquean: la sesión fallaría en silencio en parte de los navegadores.
La solución es la misma para todos los casos: el frontend hace de proxy de /api hacia la
API. El navegador ve un solo origen.
El proxy¶
Sirve para vite dev y para vite preview:
// vite.config.ts
import { taiApiProxy } from './src/lib/api/vite'
export default defineConfig({ plugins: [svelte(), taiApiProxy()] })
Reenvía /api/* a la variable de entorno API_URL, que se lee al arrancar el servidor, no
al compilar: la misma imagen sirve para dev, pre y prod, y el destino se cambia en la Web App.
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit'
export const handle: Handle = async ({ event, resolve }) => {
if (event.url.pathname.startsWith('/api/')) {
const destino = new URL(event.url.pathname.slice(4) + event.url.search, process.env.API_URL)
return fetch(destino, {
method: event.request.method, headers: event.request.headers,
body: event.request.body, duplex: 'half',
} as RequestInit)
}
return resolve(event)
}
Lo que tiene que saber la API¶
El proxy quita /api de la ruta. Para que la cookie vaya a /api/auth y la documentación enlace
bien, la API tiene que saber que se la sirve ahí. En su config.py:
Con la sesión en cookie, la API no arranca con ALLOWED_ORIGINS = ["*"], que es lo que deja
tai-api init: con credenciales, el comodín aceptaría peticiones desde cualquier sitio.
tai-api generate lee el config.py (sin ejecutarlo) y avisa de las dos cosas: un ROOT_PATH
distinto del base_path del bloque frontend —la sesión que se pierde al recargar— y el comodín
en ALLOWED_ORIGINS. Un valor que no es un literal (os.environ[...]) no se puede comprobar al
generar, y no se avisa.
En modo Keycloak, además, PUBLIC_URL es la URL de la API tal como la ve el navegador, con su
/api: https://app-x.azurewebsites.net/api. Ver Keycloak.
vite preview en producción
Es como se despliegan hoy muchos frontends, y el proxy funciona sobre él, pero la documentación de Vite lo desaconseja como servidor de producción.