← Cloudflare Workers / workers / examples
Ukládání do mezipaměti pomocí fetch
Pokud chcete rychle začít, klikněte na tlačítko níže.
Tím se vytvoří repozitář ve vašem účtu GitHub a aplikace se nasadí na Cloudflare Workers.
export default {
async fetch(request) {
const url = new URL(request.url);
// Only use the path for the cache key, removing query strings
// and always store using HTTPS, for example, https://www.example.com/file-uri-here
const someCustomKey = `https://${url.hostname}${url.pathname}`;
let response = await fetch(request, {
cf: {
// Always cache this fetch regardless of content type
// for a max of 5 seconds before revalidating the resource
cacheTtl: 5,
cacheEverything: true,
//Enterprise only feature, see Cache API for other plans
cacheKey: someCustomKey,
},
});
// Reconstruct the Response object to make its headers mutable.
response = new Response(response.body, response);
// Set cache control headers to cache on browser for 25 minutes
response.headers.set("Cache-Control", "max-age=1500");
return response;
},
};export default {
async fetch(request): Promise<Response> {
const url = new URL(request.url);
// Only use the path for the cache key, removing query strings
// and always store using HTTPS, for example, https://www.example.com/file-uri-here
const someCustomKey = `https://${url.hostname}${url.pathname}`;
let response = await fetch(request, {
cf: {
// Always cache this fetch regardless of content type
// for a max of 5 seconds before revalidating the resource
cacheTtl: 5,
cacheEverything: true,
//Enterprise only feature, see Cache API for other plans
cacheKey: someCustomKey,
},
});
// Reconstruct the Response object to make its headers mutable.
response = new Response(response.body, response);
// Set cache control headers to cache on browser for 25 minutes
response.headers.set("Cache-Control", "max-age=1500");
return response;
},
} satisfies ExportedHandler;import { Hono } from 'hono';
type Bindings = {};
const app = new Hono<{ Bindings: Bindings }>();
app.all('*', async (c) => {
const url = new URL(c.req.url);
// Only use the path for the cache key, removing query strings
// and always store using HTTPS, for example, https://www.example.com/file-uri-here
const someCustomKey = `https://${url.hostname}${url.pathname}`;
// Fetch the request with custom cache settings
let response = await fetch(c.req.raw, {
cf: {
// Always cache this fetch regardless of content type
// for a max of 5 seconds before revalidating the resource
cacheTtl: 5,
cacheEverything: true,
// Enterprise only feature, see Cache API for other plans
cacheKey: someCustomKey,
},
});
// Reconstruct the Response object to make its headers mutable
response = new Response(response.body, response);
// Set cache control headers to cache on browser for 25 minutes
response.headers.set("Cache-Control", "max-age=1500");
return response;
});
export default app;from workers import WorkerEntrypoint, Response, fetch
from urllib.parse import urlparse
class Default(WorkerEntrypoint):
async def fetch(self, request):
url = urlparse(request.url)
# Only use the path for the cache key, removing query strings
# and always store using HTTPS, for example, https://www.example.com/file-uri-here
some_custom_key = f"https://{url.hostname}{url.path}"
response = await fetch(
request,
cf={
# Always cache this fetch regardless of content type
# for a max of 5 seconds before revalidating the resource
"cacheTtl": 5,
"cacheEverything": True,
# Enterprise only feature, see Cache API for other plans
"cacheKey": some_custom_key,
},
)
# Reconstruct the Response object to make its headers mutable
new_response = Response(response.body, headers=dict(response.headers))
# Set cache control headers to cache on browser for 25 minutes
new_response.headers["Cache-Control"] = "max-age=1500"
return new_responseuse worker::*;
#[event(fetch)]
async fn fetch(req: Request, _env: Env, _ctx: Context) -> Result<Response> {
let url = req.url()?;
// Only use the path for the cache key, removing query strings
// and always store using HTTPS, for example, https://www.example.com/file-uri-here
let custom_key = format!(
"https://{host}{path}",
host = url.host_str().unwrap(),
path = url.path()
);
let request = Request::new_with_init(
url.as_str(),
&RequestInit {
headers: req.headers().clone(),
method: req.method(),
cf: CfProperties {
// Always cache this fetch regardless of content type
// for a max of 5 seconds before revalidating the resource
cache_ttl: Some(5),
cache_everything: Some(true),
// Enterprise only feature, see Cache API for other plans
cache_key: Some(custom_key),
..CfProperties::default()
},
..RequestInit::default()
},
)?;
let mut response = Fetch::Request(request).send().await?;
// Set cache control headers to cache on browser for 25 minutes
let _ = response.headers_mut().set("Cache-Control", "max-age=1500");
Ok(response)
}Ukládání HTML prostředků do mezipaměti
// Force Cloudflare to cache an asset
fetch(event.request, { cf: { cacheEverything: true } });Nastavení úrovně cache na Cache Everything přepíše výchozí cacheovatelnost daného assetu. Pro time-to-live (TTL) se Cloudflare bude i nadále spoléhat na hlavičky nastavené origin serverem.
Custom Cache Keys
To, zda jsou si dva požadavky pro účely ukládání do mezipaměti rovny, určuje jejich klíč mezipaměti. Pokud má požadavek stejný klíč mezipaměti jako nějaký předchozí požadavek, může Cloudflare poskytnout oběma stejnou odpověď uloženou v mezipaměti. Více o klíčích mezipaměti se dozvíte v Vytvoření vlastních cache keys dokumentace.
// Set cache key for this request to "some-string".
fetch(event.request, { cf: { cacheKey: "some-string" } });Cloudflare obvykle vypočítá klíč cache pro požadavek na základě adresy URL požadavku. Někdy však může být žádoucí, aby se různé adresy URL pro účely ukládání do cache považovaly za stejné. Pokud je například obsah vašeho webu hostován současně na Amazon S3 i Google Cloud Storage, máte na obou místech stejný obsah a k náhodnému rozložení zátěže mezi oběma zdroji můžete použít Worker. Zároveň však nechcete, aby se váš obsah ukládal do cache duplicitně ve dvou kopiích. V takovém případě můžete použít vlastní klíče cache, které vycházejí z adresy URL původního požadavku, a nikoli z adresy URL podřízeného požadavku (subrequest):
export default {
async fetch(request) {
let url = new URL(request.url);
if (Math.random() < 0.5) {
url.hostname = "example.s3.amazonaws.com";
} else {
url.hostname = "example.storage.googleapis.com";
}
let newRequest = new Request(url, request);
return fetch(newRequest, {
cf: { cacheKey: request.url },
});
},
};export default {
async fetch(request): Promise<Response> {
let url = new URL(request.url);
if (Math.random() < 0.5) {
url.hostname = "example.s3.amazonaws.com";
} else {
url.hostname = "example.storage.googleapis.com";
}
let newRequest = new Request(url, request);
return fetch(newRequest, {
cf: { cacheKey: request.url },
});
},
} satisfies ExportedHandler;import { Hono } from 'hono';
type Bindings = {};
const app = new Hono<{ Bindings: Bindings }>();
app.all('*', async (c) => {
const originalUrl = c.req.url;
const url = new URL(originalUrl);
// Randomly select a storage backend
if (Math.random() < 0.5) {
url.hostname = "example.s3.amazonaws.com";
} else {
url.hostname = "example.storage.googleapis.com";
}
// Create a new request to the selected backend
const newRequest = new Request(url, c.req.raw);
// Fetch using the original URL as the cache key
return fetch(newRequest, {
cf: { cacheKey: originalUrl },
});
});
export default app;Workers pracující jménem různých zón nemohou navzájem ovlivnit svou cache. Klíče cache můžete přepsat pouze u požadavků v rámci vlastní zóny (v příkladu výše event.request.url byl uložen klíč) nebo požadavky na hostitele, kteří nejsou na Cloudflare. Při odesílání požadavku do jiné zóny Cloudflare (například patřící jinému zákazníkovi Cloudflare) tato zóna plně řídí způsob, jakým je její vlastní obsah v rámci Cloudflare ukládán do mezipaměti; toto chování nelze přepsat.
Ukládání očekávaných odpovědí Vary do mezipaměti
Použijte cf.vary když origin vrátí Vary hlavičku a chcete, aby dílčí požadavek Workeru ukládal do mezipaměti očekávané varianty. Toto nastavení platí pouze pro fetch() požadavek, kde jste ji nastavili.
Podrobnosti o chování Vary najdete v Vary. Úplný objekt request init najdete v cf.vary.
export default {
async fetch(request) {
return fetch(request, {
cf: {
vary: {
default: { action: "bypass" },
headers: {
accept: {
action: "normalize",
media_types: ["text/html", "application/json"],
},
"accept-language": {
action: "normalize",
languages: ["en", "fr", "de"],
},
},
},
},
});
},
};export default {
async fetch(request): Promise<Response> {
return fetch(request, {
cf: {
vary: {
default: { action: "bypass" },
headers: {
accept: {
action: "normalize",
media_types: ["text/html", "application/json"],
},
"accept-language": {
action: "normalize",
languages: ["en", "fr", "de"],
},
},
},
},
});
},
} satisfies ExportedHandler;Přepsání na základě kódu odpovědi origin serveru
// Force response to be cached for 86400 seconds for 200 status
// codes, 1 second for 404, and do not cache 500 errors.
fetch(request, {
cf: { cacheTtlByStatus: { "200-299": 86400, 404: 1, "500-599": 0 } },
});Tato možnost je verzí cacheTtl funkci, která vybírá TTL na základě stavového kódu odpovědi a automaticky nenastavuje cacheEverything: true. Pokud odpověď na tento požadavek má odpovídající stavový kód, Cloudflare uloží obsah do cache na stanovenou dobu a přepíše direktivy cache zaslané origin serverem. Můžete si prohlédnout podrobnosti o cacheTtl funkci na stránce Request.
Přizpůsobení chování cache podle typu souboru požadavku
Pomocí vlastních klíčů cache a přepisů založených na kódu odpovědi můžete napsat Worker, který nastavuje TTL podle stavového kódu odpovědi z originu a typu požadovaného souboru.
Následující příklad ukazuje, jak toho lze využít k ukládání požadavků na streamovaná mediální data do mezipaměti:
export default {
async fetch(request) {
// Instantiate new URL to make it mutable
const newRequest = new URL(request.url);
const customCacheKey = `${newRequest.hostname}${newRequest.pathname}`;
const queryCacheKey = `${newRequest.hostname}${newRequest.pathname}${newRequest.search}`;
// Different asset types usually have different caching strategies. Most of the time media content such as audio, videos and images that are not user-generated content would not need to be updated often so a long TTL would be best. However, with HLS streaming, manifest files usually are set with short TTLs so that playback will not be affected, as this files contain the data that the player would need. By setting each caching strategy for categories of asset types in an object within an array, you can solve complex needs when it comes to media content for your application
const cacheAssets = [
{
asset: "video",
key: customCacheKey,
regex:
/(.*\/Video)|(.*\.(m4s|mp4|ts|avi|mpeg|mpg|mkv|bin|webm|vob|flv|m2ts|mts|3gp|m4v|wmv|qt))/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "image",
key: queryCacheKey,
regex:
/(.*\/Images)|(.*\.(jpg|jpeg|png|bmp|pict|tif|tiff|webp|gif|heif|exif|bat|bpg|ppm|pgn|pbm|pnm))/,
info: 0,
ok: 3600,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "frontEnd",
key: queryCacheKey,
regex: /^.*\.(css|js)/,
info: 0,
ok: 3600,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "audio",
key: customCacheKey,
regex:
/(.*\/Audio)|(.*\.(flac|aac|mp3|alac|aiff|wav|ogg|aiff|opus|ape|wma|3gp))/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "directPlay",
key: customCacheKey,
regex: /.*(\/Download)/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "manifest",
key: customCacheKey,
regex: /^.*\.(m3u8|mpd)/,
info: 0,
ok: 3,
redirects: 2,
clientError: 1,
serverError: 0,
},
];
const { asset, regex, ...cache } =
cacheAssets.find(({ regex }) => newRequest.pathname.match(regex)) ?? {};
const newResponse = await fetch(request, {
cf: {
cacheKey: cache.key,
polish: false,
cacheEverything: true,
cacheTtlByStatus: {
"100-199": cache.info,
"200-299": cache.ok,
"300-399": cache.redirects,
"400-499": cache.clientError,
"500-599": cache.serverError,
},
cacheTags: ["static"],
},
});
const response = new Response(newResponse.body, newResponse);
// For debugging purposes
response.headers.set("debug", JSON.stringify(cache));
return response;
},
};addEventListener("fetch", (event) => {
return event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
// Instantiate new URL to make it mutable
const newRequest = new URL(request.url);
// Set `const` to be used in the array later on
const customCacheKey = `${newRequest.hostname}${newRequest.pathname}`;
const queryCacheKey = `${newRequest.hostname}${newRequest.pathname}${newRequest.search}`;
// Set all variables needed to manipulate Cloudflare's cache using the fetch API in the `cf` object. You will be passing these variables in the objects down below.
const cacheAssets = [
{
asset: "video",
key: customCacheKey,
regex:
/(.*\/Video)|(.*\.(m4s|mp4|ts|avi|mpeg|mpg|mkv|bin|webm|vob|flv|m2ts|mts|3gp|m4v|wmv|qt))/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "image",
key: queryCacheKey,
regex:
/(.*\/Images)|(.*\.(jpg|jpeg|png|bmp|pict|tif|tiff|webp|gif|heif|exif|bat|bpg|ppm|pgn|pbm|pnm))/,
info: 0,
ok: 3600,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "frontEnd",
key: queryCacheKey,
regex: /^.*\.(css|js)/,
info: 0,
ok: 3600,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "audio",
key: customCacheKey,
regex:
/(.*\/Audio)|(.*\.(flac|aac|mp3|alac|aiff|wav|ogg|aiff|opus|ape|wma|3gp))/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "directPlay",
key: customCacheKey,
regex: /.*(\/Download)/,
info: 0,
ok: 31556952,
redirects: 30,
clientError: 10,
serverError: 0,
},
{
asset: "manifest",
key: customCacheKey,
regex: /^.*\.(m3u8|mpd)/,
info: 0,
ok: 3,
redirects: 2,
clientError: 1,
serverError: 0,
},
];
// the `.find` method is used to find elements in an array (`cacheAssets`), in this case, `regex`, which can passed to the .`match` method to match on file extensions to cache, since they are many media types in the array. If you want to add more types, update the array. Refer to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find for more information.
const { asset, regex, ...cache } =
cacheAssets.find(({ regex }) => newRequest.pathname.match(regex)) ?? {};
const newResponse = await fetch(request, {
cf: {
cacheKey: cache.key,
polish: false,
cacheEverything: true,
cacheTtlByStatus: {
"100-199": cache.info,
"200-299": cache.ok,
"300-399": cache.redirects,
"400-499": cache.clientError,
"500-599": cache.serverError,
},
cacheTags: ["static"],
},
});
const response = new Response(newResponse.body, newResponse);
// For debugging purposes
response.headers.set("debug", JSON.stringify(cache));
return response;
}Použití HTTP Cache API
cache režim lze nastavit v fetch možnosti.
Workers v současnosti podporují pouze no-store a no-cache režim pro řízení mezipaměti.
Pokud no-store je zadáno, cache se na cestě k origin serveru obchází a požadavek nelze ukládat do cache.
Když no-cache je zadáno, cache je vynucena revalidovat aktuálně uloženou odpověď s
origin serverem.
fetch(request, { cache: 'no-store'});
fetch(request, { cache: 'no-cache'});