コンテンツネゴシエーションとは、1 つの URL からリソースの異なる版を返し、エンドユーザー向けに体験を合わせる手法です。よくある例は、特定言語での配信(Accept-Language)、デバイス向けの最適化(User-Agent)、新しい画像形式の配信(Accept)です。
Cloudflare のグローバルネットワークは、この処理を大規模に扱う設計です。次世代画像の配信など一般的なケースでは、専用機能でネゴシエーションを簡素化できます。より独自のロジックが必要な場合は、Transform Rules、Snippets、Custom Cache Keys、Workers といったツールキットで細かく制御し、毎回適切なコンテンツを各ユーザーへ届けます。
訪問者の所在地に応じてコンテンツを返すなど、区別できる URL を作れる場合は、Transform Rule の方法が適しています。
この例では、e コマースサイトを運営しており、訪問者の国に応じて現地通貨で価格を表示します。
-
Cloudflare ダッシュボードで、Rules の Overview ページを開きます。
Overview を開く ↗ -
Create rule を選択し、URL Rewrite Rule を選びます。
-
Vary by Country - Canadaなど、分かりやすい名前を入力します。 -
If incoming requests match... で Custom filter expression を選択します。
-
When incoming requests match... の下で、次の式を作成します。
- Field:
Country - Operator:
equals - Value:
Canada
- Field:
-
Then... の下で
- Path は Preserve を選択します。
- Query は Rewrite to: Dynamic
loc=caを選択します。
-
Save を選択します。
これで、カナダからの /products/item へのリクエストは、オリジンまたはキャッシュに到達する前に /products/item?loc=ca に変換され、別のキャッシュエントリが作られます。
Vary for Images は、オリジンが対応しているバリアントを Cloudflare に伝えます。Cloudflare は各版を別々にキャッシュし、毎回オリジンへ問い合わせずに、ブラウザーへ正しい版を返します。この機能は Cloudflare API で管理します。
この機能を有効にするには、API で variants ルール を作成します。このルールは、ファイル拡張子を、オリジンが返せる画像形式に対応付けます。
たとえば、次の API 呼び出しは、.jpeg と .jpg ファイルについて、オリジンが image/webp と image/avif のバリアントを返せることを Cloudflare に伝えます。
Required API token permissions
At least one of the following token permissions is required:Zone Settings WriteZone Write
curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/cache/variants" \
--request PATCH \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"value": {
"jpeg": [
"image/webp",
"image/avif"
],
"jpg": [
"image/webp",
"image/avif"
]
}
}'ルール作成後、Cloudflare は各画像バリアント用に別のキャッシュエントリを作り、新しいブラウザーを使う訪問者のパフォーマンスが向上します。
Snippets は、Cloudflare を通るリクエストに対してエッジで動く、自己完結した JavaScript の fetch ハンドラーです。キャッシュキーとレスポンスの振る舞いをプログラムで制御でき、ユーザーに見える URL は変えません。
この例では、ab-test という名前の Cookie(値は group-a または group-b)で A/B テストを制御します。グループごとにページの別版をキャッシュします。
-
Cloudflare ダッシュボードで Snippets ページを開きます。
Snippets を開く ↗ -
Create new Snippet を選択し、名前を
ab-test-cachingにします。 -
次のコードを貼り付けます。
ab-testCookie に基づいてキャッシュキーを変え、レスポンスを 30 日間キャッシュします。
const CACHE_DURATION = 30 * 24 * 60 * 60; // 30 days
export default {
async fetch(request) {
// Construct a new URL for the cache key based on the A/B cookie
const abCookie = request.headers.get('Cookie')?.match(/ab-test=([^;]+)/)?.[1] || 'control';
const url = new URL(request.url);
url.pathname = `/ab-test/${abCookie}${url.pathname}`;
const cacheKey = new Request(url, request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
// If not in cache, fetch from origin
response = await fetch(request);
response = new Response(response.body, response);
response.headers.set("Cache-Control", `s-maxage=${CACHE_DURATION}`);
// Put the response into cache with the custom key
await cache.put(cacheKey, response.clone());
}
return response;
},
};- Snippet を保存してデプロイします。
- Snippets ダッシュボードから Attach to routes を選択し、Snippet を割り当てます。
アカウントが Enterprise プランの場合、Custom Cache Keys 機能で、キャッシュキーに含めるリクエスト属性をノーコードの画面から定義できます。
Custom Cache Key のオプション:
- デバイスタイプでキャッシュする
- クエリ文字列オプション
No query string parameters except - ヘッダーと値を含める
- Cookie 名と値を含める
- ユーザー: デバイスタイプ、国、言語
オリジンが同じ URL で、Accept ヘッダーに応じて異なるコンテンツタイプ(例: application/json と text/html)を返す場合は、Custom Cache Key を使って別々にキャッシュします。
-
Cloudflare ダッシュボードで Cache Rules ページを開きます。
Cache Rules を開く ↗ -
Create rule を選択します。
-
Vary by Accept Headerなど、ルール名を入力します。 -
ルールを適用する条件を設定します(特定のホスト名やパスなど)。
-
Cache key の下で Use custom key を選択します。
-
Add new を選択します。
- Type:
Header - Name:
Accept - Value: 各
valueを追加するか、すべて対象にする場合は空のままにします。
- Type:
-
Deploy を選択します。
この設定は、Accept ヘッダーの値に応じて別のキャッシュエントリを作り、API のコンテンツネゴシエーションに従います。
複雑なキャッシュのシナリオでは、Cloudflare Workers が、規模に応じた独自ロジック向けのフルなサーバーレス環境になります。
この Worker は、訪問者がモバイルかデスクトップかを判定し、それぞれ別のキャッシュエントリを作ります。正しいサイト版を配信し、キャッシュできます。
export default {
async fetch(request, env, ctx) {
const userAgent = request.headers.get('User-Agent') || '';
const deviceType = userAgent.includes('Mobile') ? 'mobile' : 'desktop';
// Create a new URL for the cache key that includes the device type
const url = new URL(request.url);
url.pathname = `/${deviceType}${url.pathname}`;
const cacheKey = new Request(url, request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
console.log(`Cache miss for ${deviceType} device. Fetching from origin.`);
response = await fetch(request);
let responseToCache = response.clone();
ctx.waitUntil(cache.put(cacheKey, responseToCache));
}
return response;
},
};この Worker は、訪問者がモバイルかデスクトップかを判定し、それぞれ別のキャッシュエントリを作ります。正しいサイト版を配信し、キャッシュできます。Enterprise の cf.customCacheKey 機能を使います。
export default {
async fetch(request) {
// 1. Determine the device type from the User-Agent header
const userAgent = request.headers.get('User-Agent') || '';
const deviceType = userAgent.includes('Mobile') ? 'mobile' : 'desktop';
// 2. Create a custom cache key by appending the device type to the URL
const customCacheKey = `${request.url}-${deviceType}`;
// 3. Fetch the response. Cloudflare's cache automatically uses the
// customCacheKey for cache operations (match, put).
const response = await fetch(request, {
cf: {
cacheKey: customCacheKey,
},
});
// Optionally, you can modify the response before returning it
// For example, add a header to indicate which cache key was used
const newResponse = new Response(response.body, response);
newResponse.headers.set("X-Cache-Key", customCacheKey);
return newResponse;
},
};よくある課題は、Next.js のようなフレームワークからのコンテンツをキャッシュすることです。Next.js は同じ URL に対して、HTML のページ読み込みと RSC データペイロードを区別するために RSC(React Server Components)リクエストヘッダーを使います。次の方法が適しています。
いちばん簡単な方法は、RSC ヘッダーを確認して一意のクエリパラメーターをリクエストに付ける Transform Rule を作ることです。キャッシュ可能な URL が 2 つできます。HTML 用の /page と、RSC ペイロード用の /page?_rsc=1 です。
-
Cloudflare ダッシュボードで、Rules の Overview ページを開きます。
Overview を開く ↗ -
Create rule を選択し、URL Rewrite Rule を選びます。
-
Vary by RSC Headerなど、名前を入力します。 -
If incoming requests match で Custom filter expression を選択します。
-
When incoming requests match の下で、式を手動編集し、
RSCヘッダーの有無を確認します。has_key(http.request.headers, "rsc")
-
Then の下で:
- Path は Preserve を選択します。
- Query は Rewrite to を選び、Static:
_rsc=1を選択します。
-
Save を選択します。
別の方法として、Snippets または Custom Cache Keys を使い、見える URL は変えずに RSC ヘッダーをキャッシュキーへ直接追加します。URL はすっきりしますが、設定はより高度になります。