Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

Snippets と Workers の使い分け

最終更新 Markdown で表示Agent セットアップ

このガイドは、Cloudflare のグローバルネットワークで Snippets と Workers のどちらを使うかを判断するときに使います。ベストプラクティス、比較、実際のユースケースを示し、ワークロードに合う製品を選べるようにします。

Snippets とは

Cloudflare Snippets は、フルスタックのコンピュート基盤を用意せずに、エッジで HTTP リクエストとレスポンスをすばやく宣言的に変更する手段です。Snippets は Cloudflare Rules を拡張し、オリジンへ届く前のリクエストと、上流から戻ったあとのレスポンスを、JavaScript ベースのロジックで変更できます。

Snippets では次ができます。

  • ヘッダーの変更、JWT の検証、複雑なリライトやリダイレクト。
  • 失敗したリクエストを別オリジンへリトライし、独自のキャッシュ戦略を適用する。
  • 複数の Snippet を順に実行し、各 Snippet がリクエストまたはレスポンスを変更して次へ渡す。

Snippets は すべての有料プラン に追加料金なしで含まれます。軽量なエッジロジックには、こちらが第一候補です。

Workers とは

一方、Cloudflare Workers は、状態、コンピュート、Cloudflare の Developer Platform との連携が必要なアプリケーション向けのフルスタックコンピュート基盤です。Workers は 従量課金 で、無料枠もあります。


製品の選び方

Snippets は、エッジでの高速かつ追加料金なしのリクエスト/レスポンス変更に向いています。Cloudflare Rules を、追加インフラや外部ソリューションなしで拡張できます。

Snippets を使う場合

  • Cloudflare のネットワーク上で直接適用する、超高速なトラフィック変更。
  • 組み込みアクションを超えて Cloudflare Rules を拡張し、細かく制御する。
  • VCL、EdgeWorkers、オンプレミスのロジックを置き換え、CDN 移行を簡単にする。
  • ヘッダー変更、レスポンスのキャッシュ、リダイレクト。
  • JavaScript でエッジロジックを開発ワークフローへ組み込む。

Snippets が向いていない用途

主な機能


Snippets と Workers: 機能比較

機能 Snippets Workers
リクエスト属性(ヘッダー、地理位置情報、cookies など)に基づいてスクリプトを実行する
特定の URL ルートでコードを実行する
HTTP リクエスト/レスポンスを変更する、または 別のレスポンス を返す
ヘッダーを動的に 追加削除リライト する
エッジでアセットを キャッシュ する
オリジンサーバー 間でトラフィックを動的にルーティングする
リクエストの 認証、URL の 事前署名A/B テスト の実行
JavaScript と Web APIs でロジックを定義する
計算負荷の高い処理(AI画像変換 など)
永続データを保存する(KVDurable ObjectsD1 など)
APIフルスタックアプリケーション を構築する
TypeScript、Python、Rust、その他のプログラミング 言語 を使う
HTTP 以外の プロトコル をサポートする
実行 ログ を分析し、性能指標を追跡する
コマンドラインインターフェース(CLI) でデプロイする
段階的にロールアウトし、以前の バージョン へロールバックする
Smart Placement で実行を最適化する

コード例: よく使う Snippets のテンプレート

以下は、Snippets の実際の使い方です。使い始めのテンプレートは にもあります。

HTTP ヘッダーを変更する

リクエストとレスポンスのヘッダーを動的に変更します。

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;
	},
};

カスタムのメンテナンスページを返す

オリジンが計画メンテナンス中のとき、トラフィックをメンテナンスページへ向けます。

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" } },
		);
	},
};

カスタムキャッシュ

エッジでプログラムによるキャッシュを行い、オリジン負荷を下げます。

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;
	},
};

国コードに基づくリダイレクト

訪問者の地理位置情報に基づいてリダイレクトします。

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);
	},
};

403 Forbidden を別ページへリダイレクトする

オリジンが 403 Forbidden を返した場合、訪問者を別ページへリダイレクトします。

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;
		}
	},
};

別オリジンへリトライする

元のリクエストへのレスポンスが 200 OK でもリダイレクトでもない場合、別オリジンへ送ります。

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;
	},
};

API レスポンスからフィールドを削除する

オリジンが JSON を返した場合、機密フィールドを削除してから訪問者へレスポンスを返します。

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;
		}
	},
};

CORS ヘッダーを設定する

Cross-Origin Resource Sharing(CORS) ヘッダーを調整し、プリフライトリクエストを処理します。

// 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;
	},
};

HTML ページ上のリンクをリライトする

オリジンを変更せずに、古いリンクを置き換えます。

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;
		}
	},
};

リクエストを遅くする

ルールに一致した受信リクエストに遅延を入れます。不審なリクエストに使えます。

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;
	},
};

Snippets と Workers を併用する

Snippets と Workers は役割が違いますが、複雑なトラフィックワークフローでは組み合わせて使えます。

競合を避けるため、同じ URL で動かさず、別のリクエストパスで動かしてください。それぞれのロジック内で、相手の URL をサブリクエストとして fetch し、実行とキャッシュの動きを安定させます。

例 1: Snippets と Workers の間でデータを渡す

Snippets は Worker へ届く前に受信リクエストを変更できます。Workers はその変更を読み取り、追加の変換を行い、下流へ渡せます。

Snippet: カスタムヘッダーを追加する

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: ヘッダーを読み取り、レスポンスへ追加する

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;
	},
};

結果: Snippet が X-Hex-Timestamp を設定し、Worker がそれを読み取ってオリジンへ転送します。

例 2: Snippets で Worker のレスポンスをキャッシュする

Worker が計算負荷の高い処理(画像変換など)を行い、Snippet がキャッシュ済みの結果を返して不要な Worker 実行を避けます。Workers を キャッシュの前 で動かしたくない場合に役立ちます。

Worker: レスポンスを変換してキャッシュする

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: キャッシュ済みレスポンスを返すか、Worker へ転送する

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;
	},
};

結果: 変換済みレスポンス(X-Cached-In-Workers: true)がキャッシュから返され、余分な Worker 実行を避けます(X-Retrieved-From-Workers は付きません)。キャッシュが切れると、Snippet は新しい版を取得します。


Snippets と Workers の間の移行

Snippets と Workers は同じ Workers runtime を共有します。bindings、永続ストレージ、高度な実行機能に依存しない JavaScript コードは、両者の間でそのまま移行できます。

ワークロードを Snippets へ移す場合

次に当てはまる Worker は、Snippets への移行を検討してください。

  • ヘッダー、リダイレクト、キャッシュルール、オリジンルーティングだけを変更している。
  • bindings、永続ストレージ、外部連携が不要。
  • 単純なロジックの軽量な JavaScript 関数である。
  • Pro、Business、または Enterprise プランで、回数無制限に無料で動かしたい。

Snippets へ移すと、次ができます。

  • Ruleset Engine による高度なリクエスト一致を使う。
  • 従量課金をなくす — Snippets はすべての有料プランに 追加料金なしで含まれます
  • トラフィック変更を Cloudflare Rules へ直接組み込み、管理を簡単にする。

ワークロードを Workers へ移す場合

ロジックが次に当てはまる場合は、Snippets から Workers へ移行してください。

Snippet が実行時間、メモリ、機能の上限に達した場合は、Workers へ移すと、制限なくロジックをスケールできます。


まとめ

Cloudflare Snippets は、高速で宣言的なエッジトラフィックロジック向けの本番利用可能な手段です。Cloudflare RulesDeveloper Platform の間をつなぎます。

Snippets と Workers が解く問題は異なります。

  • ヘッダーのリライト、キャッシュ、リダイレクト、オリジンルーティング、カスタムレスポンス、A/B テスト、認証など、エッジでの高速で軽量なトラフィック変更には Snippets を使います。
  • Workers は、高度なコンピュート、永続状態、フルスタックアプリケーション向けです。

役に立ちましたか?