INTEGRITY Dokumentace

Kdy použít Snippets a kdy Workers

Tento návod vám pomůže určit, kdy použít Snippets a kdy Workers v globální síti Cloudflare. Obsahuje osvědčené postupy, srovnání a praktické případy použití, které vám pomohou vybrat pro vaši zátěž ten správný produkt.

Co jsou Snippets?

Cloudflare Snippets poskytují rychlý deklarativní způsob úpravy požadavků a odpovědí HTTP na edge, aniž byste potřebovali plnohodnotnou výpočetní platformu. Snippets rozšiřují Cloudflare Rules tím, že umožňuje napsat logiku založenou na JavaScriptu, která upravuje požadavky předtím, než dorazí na origin, a odpovědi poté, co se vrátí z upstreamu.

Snippets vám umožňují:

Snippets jsou bez příplatku součástí všechny placené plány, díky čemuž jsou preferovaným řešením pro odlehčenou logiku na edge.

Co jsou Workers?

Naproti tomu Cloudflare Workers poskytují plnou výpočetní platformu určenou pro aplikace vyžadující stav, výpočetní výkon a integrace s produkty Cloudflare Developer Platform. Workers pracují na cenový model založený na využití a zahrnují bezplatnou úroveň.


Výběr správného produktu

Snippets se ideálně hodí pro rychlé a bezplatné úpravy požadavků a odpovědí na edge síti. Rozšiřují Cloudflare Rules bez nutnosti další infrastruktury nebo externích řešení.

Kdy použít Snippets

K čemu Snippets nejsou určeny

Klíčové funkce


Snippets vs Workers: srovnání funkcí

Funkce Snippets Workers
Spouštění skriptů na základě atributů požadavku (například hlaviček, geolokace a cookies)
Spouštění kódu na konkrétní trase URL
Upravte HTTP požadavky/odpovědi nebo doručte jiná odpověď
Přidat, odebrat, nebo přepsat hlavičky dynamicky
Cache prostředků na edge
Dynamické směrování provozu mezi origin servery
Ověřte se požadavky, předběžné podepsání adres URL spusťte A/B testování
Definujte logiku pomocí JavaScript a Web API
Provádět výpočetně náročné úlohy (například AI, transformace obrázků)
Ukládání trvalých dat (například KV, Durable Objects, a D1)
Vytvořte API a full-stack aplikace
Použijte TypeScript, Python, Rust nebo jiný programovací jazyky
Podpora ne-HTTP protokoly
Analýza spuštění protokoly a sledovat metriky výkonu
Nasazení přes rozhraní příkazové řádky (CLI)
Nasazujte postupně a vraťte se k předchozí verze
Optimalizujte spouštění pomocí Smart Placement

Příklady kódu: šablony Common Snippets

Níže najdete praktické příklady použití, které demonstrují Snippets v praxi. Další šablony pro rychlý start najdete v Příklady sekce.

Úprava hlaviček HTTP

Dynamicky upravuje hlavičky požadavků a odpovědí.

export default {
	async fetch(request) {
		// Get the current timestamp
		const timestamp = Date.now();

		// Convert the timestamp to hexadecimal format
		const hexTimestamp = timestamp.toString(16);

		// Clone the request and add the custom header with HEX timestamp
		const modifiedRequest = new Request(request, {
			headers: new Headers(request.headers),
		});
		modifiedRequest.headers.set("X-Hex-Timestamp", hexTimestamp);

		// Pass the modified request to the origin
		const response = await fetch(modifiedRequest);

		// Clone the response so that it's no longer immutable
		const newResponse = new Response(response.body, response);

		// Add a custom header with a value to the response
		newResponse.headers.append(
			"x-snippets-hello",
			"Hello from Cloudflare Snippets",
		);

		// Delete headers from the response
		newResponse.headers.delete("x-header-to-delete");
		newResponse.headers.delete("x-header2-to-delete");

		// Adjust the value for an existing header in the response
		newResponse.headers.set("x-header-to-change", "NewValue");

		// Serve modified response to the visitor
		return newResponse;
	},
};

Zobrazení vlastní stránky údržby

Směruje provoz na stránku údržby, když váš origin prochází plánovanou údržbou.

export default {
	async fetch(request) {
		return new Response(
			`
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>We'll Be Right Back!</title>
                <style> body { font-family: Arial, sans-serif; text-align: center; padding: 20px; } </style>
            </head>
            <body>
                <h1>We'll Be Right Back!</h1>
                <p>Our site is undergoing maintenance. Check back soon!</p>
            </body>
            </html>
        `,
			{ status: 503, headers: { "Content-Type": "text/html" } },
		);
	},
};

Vlastní cache

Provádí programové ukládání do mezipaměti na edge serverech a snižuje tak zátěž originu.

const CACHE_DURATION = 30 * 24 * 60 * 60; // 30 days

export default {
	async fetch(request) {
		const cache = caches.default;
		const cacheKey = new Request(request.url, { method: "GET" });

		let response = await cache.match(cacheKey);
		if (!response) {
			response = await fetch(request);
			response = new Response(response.body, response);
			response.headers.set("Cache-Control", `s-maxage=${CACHE_DURATION}`);
			await cache.put(cacheKey, response.clone());
		}
		return response;
	},
};

Přesměrování na základě kódu země

Přesměrovává návštěvníky na základě jejich geografické polohy.

export default {
	async fetch(request) {
		const country = request.cf.country;
		const redirectMap = {
			US: "https://example.com/us",
			EU: "https://example.com/eu",
		};
		if (redirectMap[country])
			return Response.redirect(redirectMap[country], 301);
		return fetch(request);
	},
};

Přesměrování 403 Forbidden na jinou stránku

Pokud origin server odpověděl s 403 Forbidden chybovém kódu přesměruje návštěvníka na jinou stránku.

export default {
	async fetch(request) {
		// Send original request to the origin
		const response = await fetch(request);
		// Check if origin responded with 403 status code
		if (response.status == 403) {
			// If so, redirect to this URL
			const destinationURL = "https://example.com";
			// With this status code
			const statusCode = 301;
			// Serve redirect
			return Response.redirect(destinationURL, statusCode);
		}
		// Otherwise, serve origin's response
		else {
			return response;
		}
	},
};

Opakování na jiném origin serveru

Pokud odpověď na původní požadavek není 200 OK nebo přesměrování odešle na jiný origin.

export default {
	async fetch(request) {
		// Send original request to the origin
		const response = await fetch(request);

		// If response is not 200 OK or a redirect, send to another origin
		if (!response.ok && !response.redirected) {
			// First, clone the original request to construct a new request
			const newRequest = new Request(request);
			// Add a header to identify a re-routed request at the new origin
			newRequest.headers.set("X-Rerouted", "1");
			// Clone the original URL
			const url = new URL(request.url);
			// Send request to a different origin / hostname
			url.hostname = "example.com";
			// Serve response to the new request from the origin
			return await fetch(url, newRequest);
		}

		// If response is 200 OK or a redirect, serve it
		return response;
	},
};

Odebrání polí z odpovědi API

Pokud origin server odpoví ve formátu JSON, před vrácením odpovědi návštěvníkovi odstraní citlivá pole.

export default {
	async fetch(request) {
		// Send original request to the origin
		const response = await fetch(request);
		// Check if origin responded with JSON
		try {
			// Parse API response as JSON
			var api_response = response.json();
			// Specify the fields you want to delete. For example, to delete "botManagement" array from parsed JSON:
			delete api_response.botManagement;
			// Serve modified API response
			return Response.json(api_response);
		} catch (err) {
			// On failure, serve unmodified origin's response
			return response;
		}
	},
};

Nastavit hlavičky CORS

Upraví Cross-Origin Resource Sharing (CORS) hlavičky a zpracovává preflight požadavky.

// Define CORS headers
const corsHeaders = {
	"Access-Control-Allow-Origin": "*", // Replace * with your allowed origin(s)
	"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", // Adjust allowed methods as needed
	"Access-Control-Allow-Headers": "Content-Type, Authorization", // Adjust allowed headers as needed
	"Access-Control-Max-Age": "86400", // Adjust max age (in seconds) as needed
};

export default {
	async fetch(request) {
		// Make a copy of the request to modify its headers
		const modifiedRequest = new Request(request);

		// Handle preflight requests (OPTIONS)
		if (request.method === "OPTIONS") {
			return new Response(null, {
				headers: {
					...corsHeaders,
				},
				status: 200, // Respond with OK status for preflight requests
			});
		}

		// Pass the modified request through to the origin
		const response = await fetch(modifiedRequest);

		// Make a copy of the response to modify its headers
		const modifiedResponse = new Response(response.body, response);

		// Set CORS headers on the response
		Object.keys(corsHeaders).forEach((header) => {
			modifiedResponse.headers.set(header, corsHeaders[header]);
		});

		return modifiedResponse;
	},
};

Nahradí zastaralé odkazy, aniž byste museli cokoli měnit na origin serveru.

export default {
	async fetch(request) {
		// Define the old hostname here.
		const OLD_URL = "oldsite.com";
		// Then add your new hostname that should replace the old one.
		const NEW_URL = "newsite.com";

		class AttributeRewriter {
			constructor(attributeName) {
				this.attributeName = attributeName;
			}
			element(element) {
				const attribute = element.getAttribute(this.attributeName);
				if (attribute) {
					element.setAttribute(
						this.attributeName,
						attribute.replace(OLD_URL, NEW_URL),
					);
				}
			}
		}

		const rewriter = new HTMLRewriter()
			.on("a", new AttributeRewriter("href"))
			.on("img", new AttributeRewriter("src"));

		const res = await fetch(request);
		const contentType = res.headers.get("Content-Type");

		// If the response is HTML, it can be transformed with
		// HTMLRewriter -- otherwise, it should pass through
		if (contentType.startsWith("text/html")) {
			return rewriter.transform(res);
		} else {
			return res;
		}
	},
};

Zpomalení požadavků

Definuje zpoždění, které se použije, pokud příchozí požadavky odpovídají vašemu pravidlu. Užitečné pro podezřelé požadavky.

export default {
	async fetch(request) {
		// Define delay
		const delay_in_seconds = 5;
		// Introduce a delay
		await new Promise((resolve) =>
			setTimeout(resolve, delay_in_seconds * 1000),
		); // Set delay in milliseconds

		// Pass the request to the origin
		const response = await fetch(request);
		return response;
	},
};

Společné používání Snippets a Workers

Snippets a Workers mají odlišné možnosti, ale dokážou spolupracovat při zpracování složitých pracovních postupů provozu.

Aby nedocházelo ke konfliktům, měly by Snippets a Workers pracovat na oddělených cestách požadavků, nikoli běžet na stejné URL adrese. Nechte je načítat příslušné URL adresy jako subrequest v rámci vlastní logiky, čímž zajistíte plynulé provádění a správné chování cache.

Příklad 1: Předávání dat mezi Snippets a Workers

Snippets mohou upravit příchozí požadavky ještě předtím, než dorazí k Workeru, a Workers pak mohou tyto úpravy přečíst, provést další transformace a předat požadavek dál.

Snippet: přidání vlastní hlavičky

export default {
	async fetch(request) {
		// Get the current timestamp
		const timestamp = Date.now();
		const hexTimestamp = timestamp.toString(16);

		// Clone request and add a custom header
		const modifiedRequest = new Request(request, {
			headers: new Headers(request.headers),
		});
		modifiedRequest.headers.set("X-Hex-Timestamp", hexTimestamp);

		console.log(`X-Hex-Timestamp: ${hexTimestamp}`);

		// Pass modified request to origin
		return fetch(modifiedRequest);
	},
};

Worker: Přečtení hlavičky a její přidání do odpovědi

export default {
	async fetch(request) {
		const response = await fetch("https://{snippets_url}", request); // Ensure {snippets_url} points to the endpoint modified by Snippets
		const newResponse = new Response(response.body, response);

		let hexTimestamp = request.headers.get("X-Hex-Timestamp") || "null";
		console.log(hexTimestamp);

		newResponse.headers.set("X-Hex-Timestamp", hexTimestamp);
		return newResponse;
	},
};

Výsledek: Snippet nastavuje X-Hex-Timestamp, který Worker čte a předává origin serveru.

Příklad 2: Ukládání odpovědí Worker do mezipaměti pomocí Snippets

Worker provádí výpočetně náročné zpracování (například transformaci obrázků), zatímco Snippet obsluhuje výsledky z mezipaměti, aby se předešlo zbytečnému spouštění Workeru. To se hodí v situacích, kdy spouštění Workers před mezipamětí není žádoucí.

Worker: Transformace a ukládání odpovědí do mezipaměti

export default {
	async fetch(request) {
		const url = new URL(request.url);
		url.hostname = "origin.example.com"; // Ensure this hostname points to the origin where the resource is hosted

		const newRequest = new Request(url, request);
		const customKey = `https://${url.hostname}${url.pathname}`; // This custom cache key should be the same in both Worker and Snippet configuration for cache to work

		// Fetch and modify response
		const response = await fetch(newRequest);
		const newResponse = new Response(response.body, response);

		// Cache the transformed response
		const cache = caches.default;
		const cachedResponse = newResponse.clone();
		cachedResponse.headers.set("X-Cached-In-Workers", "true");
		await cache.put(customKey, cachedResponse);

		newResponse.headers.set("X-Retrieved-From-Workers", "true");
		return newResponse;
	},
};

Snippet: doručení odpovědí z cache nebo předání Workeru

export default {
	async fetch(request) {
		const url = new URL(request.url);
		url.hostname = "origin.example.com"; // Ensure this hostname points to the origin where the resource is hosted
		const cacheKey = `https://${url.hostname}${url.pathname}`; // This custom cache key should be the same in both Worker and Snippet configuration for cache to work

		// Access cache
		const cache = caches.default;
		let response = await cache.match(cacheKey);

		if (!response) {
			console.log(`Cache miss for: ${cacheKey}. Fetching from Worker...`);
			url.hostname = "worker.example.com"; // Ensure this hostname points to the Workers route
			response = await fetch(new Request(url, request));

			// Cache the response for future use
			response = new Response(response.body, response);
			response.headers.set("Cache-Control", `s-maxage=3600`);
			response.headers.set("x-snippets-cache", "stored");
		} else {
			console.log(`Cache hit for: ${cacheKey}`);
			response = new Response(response.body, response);
			response.headers.set("x-snippets-cache", "hit");
		}

		return response;
	},
};

Výsledek: Transformovaná odpověď (X-Cached-In-Workers: true) se obsluhuje z cache, čímž se předchází zbytečnému spouštění Workeru (X-Retrieved-From-Workers není přítomna). Po vypršení platnosti mezipaměti si Snippet vyžádá novou verzi.


Migrace mezi Snippets a Workers

Snippets a Workers sdílejí stejné Workers runtime, což znamená, že kód JavaScript, který nezávisí na bindings, trvalém úložišti ani pokročilých spouštěcích funkcích, lze mezi nimi bez problémů přenášet.

Kdy migrovat úlohy na Snippets

Migraci Worker na Snippets byste měli zvážit, pokud:

Přechod na Snippets vám umožňuje:

Kdy migrovat úlohy na Workers

Ze Snippets na Workers byste měli přejít, pokud vaše logika:

Pokud váš Snippet narazí na limity doby běhu, paměti nebo funkčnosti, přechod na Workers zajistí, že se vaše logika bude moci škálovat bez omezení.


Závěr

Cloudflare Snippets nabízí produkčně připravené řešení pro rychlou deklarativní logiku provozu na edge a překlenují propast mezi Cloudflare Rules a Developer Platform.

Snippets a Workers řeší odlišné problémy: