← Правила Cloudflare / rules / snippets
Когда использовать Snippets, а когда Workers
Это руководство поможет вам понять, когда использовать Snippets, а когда Workers в глобальной сети Cloudflare. В нем приведены рекомендации, сравнения и примеры из практики, которые помогут выбрать подходящий продукт для вашей задачи.
Что такое Snippets?
Cloudflare Snippets предоставляют быстрый декларативный способ изменять запросы и ответы HTTP на edge, не требуя полноценной вычислительной платформы. Snippets расширяют Cloudflare Rules позволяя писать логику на JavaScript, которая изменяет запросы до того, как они достигнут источника, и ответы после того, как они вернутся от вышестоящего сервера.
С помощью Snippets вы можете:
- Изменяйте заголовки, проверяйте JWT и реализуйте сложные переписывания или перенаправления.
- Повторяет неудачные запросы к другим источникам и применяет пользовательские стратегии кеширования.
- Последовательное выполнение нескольких Snippets, при этом каждый Snippet изменяет запрос или ответ, прежде чем передать его следующему.
Snippets включены без дополнительной платы в все платные тарифные планы, что делает их предпочтительным решением для лёгкой логики на периферии сети.
Что такое Workers?
В отличие от этого, Cloudflare Workers предоставляют full-stack платформу для вычислений, разработанную для приложений, которым необходимы состояние, вычисления и интеграции с Developer Platform. Workers работают на основе модель ценообразования на основе использования и включают бесплатный уровень.
Выбор подходящего продукта
Snippets отлично подходят для быстрых и бесплатных изменений запросов и ответов на периферии сети. Они расширяют Cloudflare Rules без необходимости в дополнительной инфраструктуре или внешних решениях.
Когда использовать Snippets
- Сверхбыстрые изменения трафика, применяемые непосредственно в сети Cloudflare.
- Расширьте возможности Cloudflare Rules за пределы встроенных действий для более точного контроля.
- Упростите миграцию CDN, заменив VCL, EdgeWorkers или локальную логику.
- Изменяйте заголовки, кешируйте ответы и выполняйте перенаправления.
- Интеграция периферийной логики в процессы разработки с помощью JavaScript.
Для чего Snippets не предназначены
- Управление постоянным состоянием (например, хранилище сеансов или базы данных).
- Ресурсоёмкие задачи (например, преобразование изображений или AI-инференс).
- Глубокие интеграции с Developer Platform такие сервисы, как Durable Objects или D1.
- Варианты использования, требующие расширенных runtime-функций, например:
Ключевые функции
- Сверхбыстрое выполнение, оптимизированное для периферийной сети, на основе Ruleset Engine и Среда выполнения Workers.
- Включено без дополнительной платы в все платные тарифные планы.
- Детальное сопоставление запросов с использованием десятков атрибутов запроса, таких как URI, user-agent, а также файлы cookie.
- Последовательное выполнение нескольких Snippets может выполняться к одному и тому же запросу, применяя изменения последовательно.
- Встроенная интеграция с Cloudflare Rules Snippets наследуют изменения запроса из других продуктов, выполняющихся на более ранних этапы запроса.
- Поддержка JavaScript и Web API, включая:
- Обязательные Среда выполнения Workers функции, такие как:
- Автоматическое развёртывание и управление версиями через Terraform.
Snippets vs Workers: сравнение функций
| Возможность | Snippets | Workers |
|---|---|---|
| Выполнение скриптов на основе атрибутов запроса (например, заголовков, геолокации и файлов cookie) | ✅ | ❌ |
| Выполнение кода для определённого маршрута URL | ✅ | ✅ |
| Изменяйте HTTP запросы/ответы или отдавайте другой ответ | ✅ | ✅ |
| Add, удалить, или перезапись заголовки динамически | ✅ | ✅ |
| Кеш ресурсы на периферийных серверах | ✅ | ✅ |
| Динамически распределяйте трафик между исходные серверы | ✅ | ✅ |
| Аутентификация запросов, предварительная подпись URL-адресов выполните A/B тестирование | ✅ | ✅ |
| Определяйте логику с помощью JavaScript и Web API | ✅ | ✅ |
| Выполнение ресурсоёмких задач (например, AI, преобразования изображений) | ❌ | ✅ |
| Хранение постоянных данных (например, KV, Durable Objects, а также D1) | ❌ | ✅ |
| Создайте API и full-stack приложения | ❌ | ✅ |
| Используйте TypeScript, Python, Rust или другой язык программирования языки | ❌ | ✅ |
| Поддержка не-HTTP протоколы | ❌ | ✅ |
| Анализ выполнения журналы и отслеживать показатели производительности | ❌ | ✅ |
| Развёртывание через интерфейс командной строки (CLI) | ❌ | ✅ |
| Постепенное развёртывание, откат к предыдущей версии | ❌ | ✅ |
| Оптимизация выполнения с помощью Smart Placement | ❌ | ✅ |
Примеры кода: шаблоны Common 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 разные возможности, их можно использовать вместе для решения сложных задач обработки трафика.
Чтобы избежать конфликтов, Snippets и Workers должны работать с разными путями запросов, а не с одним и тем же URL-адресом. Настройте их так, чтобы каждый обращался к своему URL-адресу через подзапрос внутри своей логики: это обеспечит стабильное выполнение и корректное кеширование.
Пример 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. Кеширование ответов Worker с помощью Snippets
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, то есть код JavaScript, не использующий привязки (bindings), постоянное хранилище или расширенные функции выполнения, можно переносить между ними без изменений.
Когда переносить нагрузки на Snippets
Рассмотрите миграцию Worker на Snippets, если он:
- Изменяет только заголовки, переадресацию, правила кеширования или маршрутизацию к источнику.
- Не требует bindings, постоянного хранилища или внешних интеграций.
- Представляет собой легковесную функцию JavaScript с простой логикой.
- Должен выполняться неограниченное количество раз бесплатно на тарифах Pro, Business или Enterprise.
Миграция на Snippets позволяет:
- Используйте расширенное сопоставление запросов с помощью Ruleset Engine.
- Никакой оплаты по факту использования: Snippets включено бесплатно на всех платных тарифных планах.
- Упростите управление, интегрировав изменения трафика непосредственно в Cloudflare Rules.
Когда переносить нагрузки на Workers
Перейдите со Snippets на Workers, если ваша логика:
- Превышены время выполнения, память или другие ограничения.
- Требует управления постоянным состоянием, например:
- Выполняет ресурсоёмкие вычислительные операции, включая:
- Взаимодействует с Cloudflare Developer Platform.
- Требует модульное тестирование.
- Требуется автоматизация развёртывания через CLI (Wrangler).
Если ваш Snippet достигает ограничений по времени выполнения, памяти или функциональности, переход на Workers обеспечит масштабируемость вашей логики без ограничений.
Заключение
Cloudflare Snippets предлагают готовое к продакшену решение для быстрой декларативной логики трафика на edge, устраняя разрыв между Cloudflare Rules и Developer Platform.
Snippets и Workers решают разные задачи:
- Используйте Snippets для быстрых и легковесных изменений трафика на edge, включая перезапись заголовков, кеширование, редиректы, маршрутизацию на источник, пользовательские ответы, A/B-тестирование и аутентификацию.
- Workers предназначены для сложных вычислений, постоянного состояния и full-stack приложений.