← Cloudflare Workers / workers / static-assets / routing
Generování statických stránek (SSG) a vlastní stránky 404
Aplikace s generováním statických stránek (SSG) jsou webové aplikace, které jsou z větší části sestaveny, neboli „přerenderovány“, předem. Často se vytvářejí pomocí frameworku, jako je Gatsby nebo Docusaurus. Build proces těchto frameworků vygeneruje řadu HTML souborů a doprovodných zdrojů na straně klienta (například JavaScript bundly, CSS styly, obrázky, fonty a podobně). Data jsou buď statická a zkompilovaná do HTML již při buildu, nebo si je klient načítá z API pomocí požadavků na straně klienta.
SSG framework vám často umožní vytvořit vlastní stránku 404.
Konfigurace
Chcete-li nasadit aplikaci typu Static Site Generation do Workers, musíte nakonfigurovat assets.directory, a volitelně assets.not_found_handling a assets.html_handling možnosti ve svém Konfigurační soubor Wrangler:
{
"name": "my-worker",
// Set this to today's date
"compatibility_date": "2026-08-28",
"assets": {
"directory": "./dist/",
"not_found_handling": "404-page",
"html_handling": "auto-trailing-slash"
}
}name = "my-worker"
# Set this to today's date
compatibility_date = "2026-08-28"
[assets]
directory = "./dist/"
not_found_handling = "404-page"
html_handling = "auto-trailing-slash"assets.html_handling má výchozí hodnotu auto-trailing-slash a to obvykle automaticky zajistí požadované chování: jednotlivé soubory (např. foo.html) se obslouží bez koncové lomítko a indexové soubory složek (např. foo/index.html) se obslouží s koncové lomítko. Případně můžete vynutit koncová lomítka (force-trailing-slash) nebo odstraňte koncová lomítka (drop-trailing-slash) u požadavků na HTML stránky.
Vlastní stránky 404
Konfigurace assets.not_found_handling na 404-page přepisuje výchozí chování obsluhy Workers pro statické soubory. Pokud příchozí požadavek neodpovídá žádnému souboru ve assets.directory, Workers odešle obsah nejbližšího 404.html soubor s 404 Not Found stav.
Navigační požadavky
Pokud máte skript Workeru (main), mají nakonfigurováno assets.not_found_handling, a použít assets_navigation_prefers_asset_serving příznak kompatibility (nebo nastavte datum kompatibility na 2025-04-01 nebo novější), navigační požadavky nevyvolá skript Workeru. navigační požadavek je požadavek vytvořený pomocí Sec-Fetch-Mode: navigate hlavičku, kterou prohlížeče automaticky připojují při přechodu na stránku. Díky tomu se sníží počet zpoplatněných vyvolání vašeho skriptu Workeru, což se hodí zejména u aplikací náročných na klientský kód, které by jinak Worker skript vyvolávaly velmi často a zbytečně.
Callbacky na straně klienta
V některých případech může být potřeba předat hodnotu z navigačního požadavku do vašeho Worker skriptu. Pokud například fungujete jako OAuth callback, můžete očekávat požadavky na určitou trasu, například /oauth/callback?code=.... S assets_navigation_prefers_asset_serving příznak budou vaše HTML podklady obsluhovány staticky namísto vašeho Worker skriptu. V takovém případě doporučujeme, ať už jako součást klientské aplikace pro danou trasu, nebo pomocí zjednodušeného HTML souboru určeného pro konkrétní endpoint, předat hodnotu na server pomocí klientského JavaScriptu.
<!DOCTYPE html>
<html>
<head>
<title>OAuth callback</title>
</head>
<body>
<p>Loading...</p>
<script>
(async () => {
const response = await fetch("/api/oauth/callback" + window.location.search);
if (response.ok) {
window.location.href = '/';
} else {
document.querySelector('p').textContent = 'Error: ' + (await response.json()).error;
}
})();
</script>
</body>
</html>import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/api/oauth/callback") {
const code = url.searchParams.get("code");
const sessionId =
await exchangeAuthorizationCodeForAccessAndRefreshTokensAndPersistToDatabaseAndGetSessionId(
code,
);
if (sessionId) {
return new Response(null, {
headers: {
"Set-Cookie": `sessionId=${sessionId}; HttpOnly; SameSite=Strict; Secure; Path=/; Max-Age=86400`,
},
});
} else {
return Response.json(
{ error: "Invalid OAuth code. Please try again." },
{ status: 400 },
);
}
}
return new Response(null, { status: 404 });
}
}import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async fetch(request: Request) {
const url = new URL(request.url);
if (url.pathname === "/api/oauth/callback") {
const code = url.searchParams.get("code");
const sessionId = await exchangeAuthorizationCodeForAccessAndRefreshTokensAndPersistToDatabaseAndGetSessionId(code);
if (sessionId) {
return new Response(null, {
headers: {
"Set-Cookie": `sessionId=${sessionId}; HttpOnly; SameSite=Strict; Secure; Path=/; Max-Age=86400`,
},
});
} else {
return Response.json(
{ error: "Invalid OAuth code. Please try again." },
{ status: 400 }
);
}
}
return new Response(null, { status: 404 });
}
}Lokální vývoj
Pokud používáte SPA framework postavený na Vite, může vás zajímat Plugin Vite který nabízí vývojářský zážitek nativní pro Vite.
Referenční informace
Ve většině případů stačí nakonfigurovat assets.not_found_handling na 404-page poskytne požadované chování. Pokud si vytváříte vlastní framework nebo máte specifické požadavky, následující diagram vám ukáže, jak přesně se rozhodování o směrování provádí.
Kompletní diagram rozhodování o směrování
flowchart
Request@{ shape: stadium, label: "Incoming request" }
Request-->RunWorkerFirst
RunWorkerFirst@{ shape: diamond, label: "Run Worker script first?" }
RunWorkerFirst-->|Request matches run_worker_first path|WorkerScriptInvoked
RunWorkerFirst-->|Request matches run_worker_first negative path|AssetServing
RunWorkerFirst-->|No matches|RequestMatchesAsset
RequestMatchesAsset@{ shape: diamond, label: "Request matches asset?" }
RequestMatchesAsset-->|Yes|AssetServing
RequestMatchesAsset-->|No|WorkerScriptPresent
WorkerScriptPresent@{ shape: diamond, label: "Worker script present?" }
WorkerScriptPresent-->|No|AssetServing
WorkerScriptPresent-->|Yes|RequestNavigation
RequestNavigation@{ shape: diamond, label: "Request is navigation request?" }
RequestNavigation-->|No|WorkerScriptInvoked
WorkerScriptInvoked@{ shape: rect, label: "Worker script invoked" }
WorkerScriptInvoked-.->|Asset binding|AssetServing
RequestNavigation-->|Yes|AssetServing
subgraph Asset serving
AssetServing@{ shape: diamond, label: "Request matches asset?" }
AssetServing-->|Yes|AssetServed
AssetServed@{ shape: stadium, label: "**200 OK**<br />asset served" }
AssetServing-->|No|NotFoundHandling
subgraph 404-page
NotFoundHandling@{ shape: rect, label: "Request rewritten to ../404.html" }
NotFoundHandling-->404PageExists
404PageExists@{ shape: diamond, label: "HTML Page exists?" }
404PageExists-->|Yes|404PageServed
404PageExists-->|No|404PageAtIndex
404PageAtIndex@{ shape: diamond, label: "Request is for root /404.html?" }
404PageAtIndex-->|Yes|Generic404PageServed
404PageAtIndex-->|No|NotFoundHandling
Generic404PageServed@{ shape: stadium, label: "**404 Not Found**<br />null-body response served" }
404PageServed@{ shape: stadium, label: "**404 Not Found**<br />404.html page served" }
end
endPožadavky se účtují pouze v případě, že je vyvolán skript Workeru. Odtud je pak možné obsluhovat aktiva pomocí vazby assets (na diagramu výše znázorněné čárkovanou čarou).
Více o tom, jak assets přiřazujeme, se dočtete v Dokumentace ke zpracování HTML.