← Cloudflare Workers / workers / static-assets / routing
Скрипт Worker
Если у вас настроены и статические assets, и скрипт Worker, Cloudflare сначала попытается отдать статический asset, если он соответствует входящему запросу. Подробнее о том, как происходит сопоставление assets, можно узнать в Документация по обработке HTML.
Если подходящий статический ресурс не найден, Cloudflare вызовет скрипт вашего Worker.
Это позволяет легко сочетать эти две функции для создания мощных приложений (например, full-stack-приложение, или Одностраничное приложение (SPA) или Приложение на основе Static Site Generation (SSG) с API).
Контекст Cloudflare Access
Сначала запускайте скрипт вашего Worker
Можно настроить assets.run_worker_first настройка чтобы управлять тем, когда скрипт Worker выполняется относительно раздачи статических ресурсов. Это даёт больше контроля над тем, как именно и когда эти ресурсы отдаются, и может использоваться для реализации "middleware" для запросов.
Запускать Worker перед каждым запросом
Если вам нужно всегда запускать скрипт Worker перед раздачей статических ресурсов (например, вы хотите логировать запросы, выполнять проверки аутентификации, использовать HTMLRewriter, либо иным образом преобразовывать ассеты перед отдачей), установите run_worker_first к true:
{
"name": "my-worker",
// Set this to today's date
"compatibility_date": "2026-08-28",
"main": "./worker/index.ts",
"assets": {
"directory": "./dist/",
"binding": "ASSETS",
"run_worker_first": true
}
}name = "my-worker"
# Set this to today's date
compatibility_date = "2026-08-28"
main = "./worker/index.ts"
[assets]
directory = "./dist/"
binding = "ASSETS"
run_worker_first = trueimport { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async fetch(request) {
// You can perform checks before fetching assets
const user = await checkIfRequestIsAuthenticated(request);
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
// You can then just fetch the assets as normal, or you could pass in a custom Request object here if you wanted to fetch some other specific asset
const assetResponse = await this.env.ASSETS.fetch(request);
// You can return static asset response as-is, or you can transform them with something like HTMLRewriter
return new HTMLRewriter()
.on("#user", {
element(element) {
element.setInnerContent(JSON.stringify({ name: user.name }));
},
})
.transform(assetResponse);
}
}import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint<Env> {
async fetch(request: Request) {
// You can perform checks before fetching assets
const user = await checkIfRequestIsAuthenticated(request);
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
// You can then just fetch the assets as normal, or you could pass in a custom Request object here if you wanted to fetch some other specific asset
const assetResponse = await this.env.ASSETS.fetch(request);
// You can return static asset response as-is, or you can transform them with something like HTMLRewriter
return new HTMLRewriter()
.on("#user", {
element(element) {
element.setInnerContent(JSON.stringify({ name: user.name }));
},
})
.transform(assetResponse);
}
}Сначала запускать Worker для отдельных путей
Также можно настроить выборочную маршрутизацию с приоритетом Worker с помощью массива шаблонов маршрутов, что часто сочетается с single-page-application настройка. Это позволяет запускать Worker первым только для определённых маршрутов, оставляя для остальных запросов поведение по умолчанию, при котором сначала обрабатываются статические ресурсы:
{
"name": "my-worker",
// Set this to today's date
"compatibility_date": "2026-08-28",
"main": "./worker/index.ts",
"assets": {
"directory": "./dist/",
"not_found_handling": "single-page-application",
"binding": "ASSETS",
"run_worker_first": ["/oauth/callback"]
}
}name = "my-worker"
# Set this to today's date
compatibility_date = "2026-08-28"
main = "./worker/index.ts"
[assets]
directory = "./dist/"
not_found_handling = "single-page-application"
binding = "ASSETS"
run_worker_first = [ "/oauth/callback" ]import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint {
async fetch(request) {
// The only thing this Worker script does is handle an OAuth callback.
// All other requests either serve an asset that matches or serve the index.html fallback, without ever hitting this code.
const url = new URL(request.url);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const accessToken = await exchangeCodeForToken(code, state);
const sessionIdentifier = await storeTokenAndGenerateSession(accessToken);
// Redirect back to the index, but set a cookie that the front-end will use.
return new Response(null, {
headers: {
Location: "/",
"Set-Cookie": `session_token=${sessionIdentifier}; HttpOnly; Secure; SameSite=Lax; Path=/`,
},
});
}
}import { WorkerEntrypoint } from "cloudflare:workers";
export default class extends WorkerEntrypoint<Env> {
async fetch(request: Request) {
// The only thing this Worker script does is handle an OAuth callback.
// All other requests either serve an asset that matches or serve the index.html fallback, without ever hitting this code.
const url = new URL(request.url);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const accessToken = await exchangeCodeForToken(code, state);
const sessionIdentifier = await storeTokenAndGenerateSession(accessToken);
// Redirect back to the index, but set a cookie that the front-end will use.
return new Response(null, {
headers: {
Location: "/",
"Set-Cookie": `session_token=${sessionIdentifier}; HttpOnly; Secure; SameSite=Lax; Path=/`,
},
});
}
}