Cómo se resuelve cada petición
El orden determinista con el que Cloudflare decide, para cada URL, qué Worker o qué asset la atiende: del DNS al edge, la prioridad entre custom domains y routes, y la decisión entre assets y código.
Cada petición que llega a Cloudflare recorre un árbol de decisión fijo antes de que se ejecute una sola línea de tu Worker. Saber ese orden —quién resuelve el DNS, qué gana entre un custom domain y una route, cuándo se sirve un asset en lugar de tu código— transforma el enrutado de una fuente de sorpresas en un cálculo predecible. Esta lección junta las piezas de las anteriores en una sola línea de tiempo.
- Trazar el camino de una petición desde el DNS hasta el Worker.
- Ordenar la prioridad entre custom domains y routes.
- Predecir cuándo responde un asset estático y cuándo tu código.
- Diagnosticar por qué un Worker “no corre” con un método fijo.
Del DNS al edge
Antes de hablar de Workers, la petición tiene que llegar. El navegador resuelve el hostname; si su registro es proxied, el DNS de Cloudflare devuelve una IP anycast y la petición aterriza en el centro de datos más cercano. Solo entonces empieza el pipeline del edge: TLS, seguridad, caché y, en su momento, el enrutado a Workers.
Si el registro es DNS-only, nada de esto ocurre: el tráfico va directo al origen y tu Worker es invisible. El enrutado, por tanto, no empieza en tu configuración de Workers, sino en el DNS; es la premisa que desarrolla la última lección de este nivel.
flowchart TD
A[Peticion llega al edge] --> B{Casa un custom domain o una route}
B -->|No| C[Sale del enrutado de Workers y sigue al origen]
B -->|Si| D[Se elige el patron mas especifico]
D --> E{El Worker tiene assets}
E -->|No| F[Corre tu Worker]
E -->|Si| G{run_worker_first}
G -->|Si| F
G -->|No| H{Existe el asset pedido}
H -->|Si| I[Se sirve el asset sin ejecutar codigo]
H -->|No| FLéelo de arriba abajo: cada rombo es una pregunta con respuesta binaria y solo hay una salida por camino. Ese determinismo es la propiedad más valiosa del sistema: dada una URL y tu configuración, el Worker o el asset que responde está decidido de antemano.
El orden de decisión
Dentro del enrutado de Workers, la coincidencia manda. Un custom domain casa por hostname exacto; una route, por patrón, y entre routes gana la más específica. Si nada casa, la petición abandona el enrutado de Workers y sigue su camino normal, hacia la caché o el origen. Una petición ejecuta un solo Worker: no hay encadenamiento implícito entre patrones que se solapan.
Custom domains, routes y workers.dev son las tres formas de llevar tráfico a un Worker. Todas se resuelven con la misma lógica de coincidencia; workers.dev solo entra en juego para su propio subdominio, nunca para tu dominio.
El árbol completo se puede resumir en tres preguntas encadenadas, siempre en el mismo orden:
1. ¿Llega al edge?
Decisión de red. Solo si el hostname está proxied. Con DNS-only, ningún Worker se ejecuta porque el tráfico no pasa por Cloudflare.
2. ¿Qué patrón gana?
Decisión de enrutado. Entre custom domain y routes que casan, se impone el más específico, y corre un único Worker.
3. ¿Lo tapa un asset?
Decisión de contenido. Si hay assets, por defecto un fichero que casa con la URL responde antes que tu código.
Puedes poner una route delante de un custom domain: la route se evalúa antes y, si su Worker reenvía con fetch(request), la petición llega al Worker-origen del custom domain. Es encadenamiento explícito, decidido por tu código, no por la plataforma.
Assets o Worker: quién responde primero
Cuando tu Worker lleva assets estáticos, entra la tercera decisión. El comportamiento por defecto es assets primero: si la URL casa con un fichero del directorio de assets, se sirve sin ejecutar tu código. Si no casa ningún asset y hay script, corre el Worker. Y el Worker siempre puede devolver la pelota a los assets con env.ASSETS.fetch(request):
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname.startsWith("/api/")) {
return new Response("respuesta dinamica");
}
// Delega el resto a los ficheros estaticos
return env.ASSETS.fetch(request);
},
};
Dos ajustes cambian el guion por defecto:
{
"assets": {
"directory": "./dist",
// Corre el Worker antes que los assets, con excepciones
"run_worker_first": ["/api/*", "!/api/docs/*"],
// Que hacer cuando no casa ningun asset
"not_found_handling": "single-page-application"
}
}
Con run_worker_first inviertes el orden para ciertos patrones —útil para autenticar o registrar antes de servir—; con not_found_handling decides si un fallo de asset devuelve el index.html de una SPA, una página 404 o nada. Quien migra de Pages a Workers tropieza aquí: Pages ejecutaba la función antes que el asset, y Workers hace lo contrario salvo que lo pidas.
wrangler dev reproduce este mismo árbol de decisión en tu máquina, assets incluidos. Es la forma barata de verificar quién responde a cada ruta antes de desplegar a producción.
La razón por la que el enrutado de Cloudflare parece caprichoso hasta que hace clic es que mezclamos en la cabeza tres decisiones que en realidad son secuenciales y deterministas. La primera es de red: la petición siquiera llega al edge. Solo llega si hay un registro proxied; con DNS-only, ningún Worker del mundo se ejecutará porque el tráfico ni pasa por Cloudflare. La segunda es de enrutado: entre los patrones que casan, gana el más específico, y solo uno corre. La tercera, si hay assets, es de contenido: por defecto un fichero estático que casa con la URL gana a tu código, salvo que hayas pedido run_worker_first. Casi todos los “mi Worker no corre” son un fallo en uno de esos tres escalones: DNS-only en lugar de proxied, una route menos específica que otra que la eclipsa, o un asset que sombrea la ruta que creías tuya. Convierte la sorpresa en un checklist descendente —llega al edge, qué patrón gana, lo tapa un asset— y el enrutado deja de ser magia para volverse un árbol que puedes recorrer con el dedo. Ese es exactamente el hábito que separa a quien despliega de quien opera un sistema en el edge.
- Dibuja el camino de una petición a un hostname DNS-only y explica en qué escalón muere.
- Con dos routes que casen, predice cuál Worker corre antes de probarlo; luego compruébalo.
- En un Worker con assets, pide una ruta que exista como fichero y otra que no; observa quién responde.
- Añade
run_worker_firstpara un prefijo y confirma que ahora tu código se ejecuta antes que el asset.