Текст в Expression Editor:
http.cookie contains "user_id"Выбранная операция в разделе Изменить заголовок запроса: Включить динамический режим
Имя заголовка: Cloudflare-Workers-Version-Key
Значение: http.request.cookies["user_id"][0]
← Cloudflare Workers / workers / static-assets / routing / advanced
Во время постепенное развёртывание, каждый запрос со случайной вероятностью направляется на ту или иную версию в соответствии с заданными процентами. Это означает, что одному и тому же пользователю при каждом запросе может отдаваться контент из разной версии, что может вызвать рассогласование версий проблемы.
Привязка к версии решает эту проблему за счёт детерминированного назначения пользователям версии на основе стабильного идентификатора, поэтому в течение всего постепенного развёртывания они стабильно попадают на одну и ту же версию при повторных загрузках страниц и подзапросах.
Задайте Cloudflare-Workers-Version-Key заголовок во входящем запросе к вашему Worker:
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: foo'Для заданного развёртывание, все запросы с ключом версии, установленным в foo будет обрабатываться той же версией вашего Worker. Платформа хеширует ключ и использует результат вместе с настроенными процентами, чтобы детерминированно назначить версию: вы не выбираете, какой версии соответствует ключ.
По мере продвижения постепенного развёртывания (например, с 10% до 20% и затем до 50%) пользователи, чьи ключи уже были назначены новой версии, останутся на ней. Пользователи на старой версии будут постепенно переходить на новую по мере увеличения процента, но не будут возвращаться обратно, если вы не выполните откат.
Можно задать Cloudflare-Workers-Version-Key заголовок как при внешнем запросе из интернета к вашему Worker, так и при подзапросе от одного Worker к другому с помощью привязка к сервису.
Привязка к версии особенно важна, если ваш Worker обслуживает статические ресурсы с именами файлов, содержащими хеш содержимого (например, index-a1b2c3d4.js), что является поведением по умолчанию для большинства современных инструментов сборки и фреймворков.
Во время постепенного развёртывания разные версии вашего приложения будут иметь разные имена файлов ресурсов:
assets/index-a1b2c3d4.jsassets/index-m3n4o5p6.jsБез привязки к версии пользователь может получить HTML от версии A, но когда его браузер запрашивает index-a1b2c3d4.js, такой запрос может быть направлен на версию B, у которой этого файла нет, что приведёт к ошибке 404 и неработающей странице.
Настройка привязки к версии с помощью любого из методов, описанных в Выберите ключ версии полностью исключает эту проблему, гарантируя, что все запросы от одного пользователя направляются на одну и ту же версию.
Правильный ключ версии зависит от того, какие стабильные идентификаторы доступны в вашем приложении. Вы можете задать заголовок с помощью Transform Rule в вашей зоне, который извлекает значения из запроса без изменения кода вашего приложения.
Если у вашего приложения есть идентификатор пользователя в cookie или заголовке, это лучший вариант. Каждый пользователь детерминированно закрепляется за одной версией и сохраняет эту привязку между сессиями, устройствами и перезагрузками.
Текст в Expression Editor:
http.cookie contains "user_id"Выбранная операция в разделе Изменить заголовок запроса: Включить динамический режим
Имя заголовка: Cloudflare-Workers-Version-Key
Значение: http.request.cookies["user_id"][0]
Если ваше приложение устанавливает сессионную cookie, используйте идентификатор сессии. Это обеспечивает согласованную маршрутизацию на протяжении всей сессии. Если сессия истекает и создаётся новая, пользователь может быть назначен на другую версию.
Текст в Expression Editor:
http.cookie contains "session_id"Выбранная операция в разделе Изменить заголовок запроса: Включить динамический режим
Имя заголовка: Cloudflare-Workers-Version-Key
Значение: http.request.cookies["session_id"][0]
Если в запросе вашего приложения нет стабильного идентификатора, у вас есть два варианта:
Вариант 1: используйте IP-адрес клиента. Это самый простой подход, не требующий изменений в приложении. Пользователи за одним и тем же NAT или VPN будут сгруппированы вместе, а мобильные пользователи, переключающие сети, могут менять версию, но для большинства приложений это значительно снижает переключения между версиями по сравнению со случайной маршрутизацией на уровне запроса.
Текст в Expression Editor:
trueВыбранная операция в разделе Изменить заголовок запроса: Включить динамический режим
Имя заголовка: Cloudflare-Workers-Version-Key
Значение: ip.src
Вариант 2: установите долгоживущий cookie из вашего Worker. При первом запросе (для которого версия будет назначена случайно) ваш Worker генерирует стабильный идентификатор и устанавливает его в cookie. Все последующие запросы используют этот cookie в качестве ключа версии. Такой подход обеспечивает наилучшую согласованность для анонимных пользователей ценой небольшого объёма дополнительного кода приложения.
export default {
async fetch(request, env) {
const response = await handleRequest(request, env);
// Set a long-lived cookie to use as a version affinity key.
const COOKIE_NAME = "version-key"; // can be any name
const cookieHeader = request.headers.get("Cookie") ?? "";
const hasAffinityCookie = new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=`).test(
cookieHeader,
);
if (!hasAffinityCookie) {
const id = crypto.randomUUID();
response.headers.append(
"Set-Cookie",
`${COOKIE_NAME}=${id}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=31536000`,
);
}
return response;
},
};export default {
async fetch(request: Request, env: Env): Promise<Response> {
const response = await handleRequest(request, env);
// Set a long-lived cookie to use as a version affinity key.
const COOKIE_NAME = "version-key"; // can be any name
const cookieHeader = request.headers.get("Cookie") ?? "";
const hasAffinityCookie = new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=`).test(cookieHeader);
if (!hasAffinityCookie) {
const id = crypto.randomUUID();
response.headers.append(
"Set-Cookie",
`${COOKIE_NAME}=${id}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=31536000`,
);
}
return response;
},
};Затем создайте Transform Rule, чтобы использовать этот cookie в качестве ключа версии:
Текст в Expression Editor:
http.cookie contains "version-key"Выбранная операция в разделе Изменить заголовок запроса: Включить динамический режим
Имя заголовка: Cloudflare-Workers-Version-Key
Значение: http.request.cookies["version-key"][0]
Работу version affinity можно проверить, отправив несколько запросов с одним и тем же version key и убедившись, что все они обрабатываются одной и той же версией:
# Both requests should return responses from the same version
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'Используйте привязка метаданных версии чтобы включать идентификатор версии в ответ вашего Worker во время тестирования.
Во время постепенных развёртываний следите за аналитикой Worker на предмет роста доли ответов 404, особенно для файлов ресурсов (.js, .css, .png). Используйте Analytics Engine или Logpush для отслеживания этих метрик и раннего выявления проблем с рассинхронизацией версий. Если вы заметили проблемы, можно откатить к предыдущей версии.