Введение
Веб-сайт может запоминать настройки отображения, например тёмную тему или предпочитаемый язык. Обычно такие настройки читаются при каждом посещении, но изменяются лишь иногда, поэтому они хорошо подходят для примера с Workers KV. Вместо хранения одного слова в качестве флага функции вы сохраните JSON — текст, который объединяет именованные поля в одно значение. Worker преобразует этот текст обратно в пригодные для использования настройки.
В этой лабораторной работе Alice и Bob — вымышленные обозначения аккаунтов, а не реальные пользователи. Вы зададите для них разные настройки и сделаете так, чтобы для отсутствующих или повреждённых записей возвращалось разумное значение по умолчанию. Вы также добавите метаданные — небольшое описание, хранящееся рядом со значением, — чтобы указывать ревизию настройки. Номера ревизий помогают понять, какие данные были прочитаны; они не гарантируют, что во всех местоположениях новое значение станет доступно немедленно.
Сначала завершите лабораторную работу Create a Feature Flag Store. Эта лабораторная работа начинается в новой виртуальной машине в каталоге /home/labex/project/account-preferences; Node.js 22.22.0 и локальный для проекта Wrangler 4.131.1 уже установлены. Вы создадите новый Worker и пространство имён в учебном аккаунте, используя те же разрешения на чтение аккаунта, запись Workers и запись KV. В общедоступной демонстрации выдаются только искусственные настройки отображения; обозначение аккаунта в URL не является аутентификацией. Для этого небольшого упражнения не нужны платное обновление тарифа или собственный домен. Перед выходом из виртуальной машины завершите очистку ресурсов.
Подключение пространства имён настроек
На этом шаге вы подключите отдельное пространство имён для демонстрационных настроек аккаунтов. Пространство имён объединяет значения этого сервиса, а привязка PREFERENCES задаёт стабильное имя, через которое Worker обращается к нему. Эта новая виртуальная машина использует сохранённые сведения об аккаунте, но не пространство имён и авторизацию из предыдущей лабораторной работы.
Перейдите в подготовленный проект:
cd /home/labex/project/account-preferences
Один раз сгенерируйте уникальное имя. Команда openssl rand -hex 6 выводит случайный суффикс, а $(...) вставляет его в имя. Переменная оболочки сохранит это имя для следующих команд в данном терминале.
WORKER_NAME="labex-prefs-$(openssl rand -hex 6)"
printf '%s\n' "$WORKER_NAME"
Авторизуйте эту виртуальную машину. Помимо чтения идентификатора аккаунта, разрешение Workers Scripts Write позволяет выполнять развёртывание и удаление, а Workers KV Write — управлять пространством имён и ключами этой лабораторной работы.
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_kv:write
Откройте показанную ссылку для устройства в браузере, введите текущий код, проверьте запрошенные разрешения и учебный аккаунт, затем авторизуйте Wrangler. На странице подтверждения также может отображаться доступ в фоновом режиме. Вернитесь в терминал и дождитесь завершения входа.
Разверните раздел Developer Platform, чтобы проверить разрешения Workers Scripts Write и Workers KV Storage Write. Это те же разрешения на управление ресурсами, которые были представлены в Create a Feature Flag Store.
npx wrangler whoami --json
Убедитесь, что указано loggedIn: true, а также имя name учебного аккаунта, даже если в списке присутствует только один аккаунт. Скопируйте id этого аккаунта. Сохраните его в конфигурации ниже, заменив YOUR_ACCOUNT_ID перед выполнением команды. Здесь документ cat записывает всё содержимое между двумя строками JSON в файл, а > заменяет файл. Разделитель без кавычек позволяет оболочке подставить значение $WORKER_NAME.
cat > wrangler.jsonc <<JSON
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-07-30",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": true
}
JSON
Создайте пространство имён в этом аккаунте. Его название содержит уникальное имя Worker, чтобы позднее вы могли легко сопоставить эти ресурсы. Параметр --update-config=false оставляет редактирование привязки вам, вместо того чтобы автоматически изменять файл.
npx wrangler kv namespace create "$WORKER_NAME-preferences" --update-config=false
В выводе появится новый идентификатор пространства имён. Скопируйте его, затем замените YOUR_ACCOUNT_ID и YOUR_NAMESPACE_ID в этой полной конфигурации. Имя привязки PREFERENCES выбирается для вашего кода, а идентификатор указывает на реальный ресурс Cloudflare.
cat > wrangler.jsonc <<JSON
{
"name": "$WORKER_NAME",
"main": "src/index.js",
"compatibility_date": "2026-07-30",
"account_id": "YOUR_ACCOUNT_ID",
"workers_dev": true,
"kv_namespaces": [
{ "binding": "PREFERENCES", "id": "YOUR_NAMESPACE_ID" }
]
}
JSON
npx wrangler kv namespace list
Найдите название пространства имён этой лабораторной работы и сравните его идентификатор с указанным в файле. Другие пространства имён могут присутствовать — не изменяйте их. Эта конфигурация указывает, какой аккаунт и какой ресурс должны использовать последующие команды. Привязка — это ссылка на пространство имён, а не копия его данных.
Сохранение JSON-значений и метаданных ревизий
На этом шаге вы подготовите небольшой набор данных с обычными настройками и двумя реалистичными ошибками в данных. В JSON для имён полей и строк используются двойные кавычки. Одинарные кавычки вокруг аргумента команды не дают оболочке интерпретировать эти кавычки JSON.
Запишите локальные записи. Alice предпочитает тёмную тему и английский язык, а Bob — светлую тему и французский язык. Параметр --metadata добавляет к ключу отдельный объект JSON. В данном случае его число revision обозначает сохранённую версию, а не решение по безопасности и не автоматический счётчик обновлений.
npx wrangler kv key put account:alice '{"theme":"dark","language":"en"}' --binding PREFERENCES --local --metadata '{"revision":7}'
npx wrangler kv key put account:bob '{"theme":"light","language":"fr"}' --binding PREFERENCES --local --metadata '{"revision":8}'
npx wrangler kv key put account:broken 'not-json' --binding PREFERENCES --local
npx wrangler kv key put account:invalid '{"theme":"neon","language":"en"}' --binding PREFERENCES --local
account:broken содержит текст, который нельзя разобрать как JSON. account:invalid содержит корректный JSON, но задаёт тему, которую приложение не поддерживает. Наличие обоих случаев помогает различать разбор — чтение структуры текста, — и проверку — определение того, имеют ли его поля смысл для приложения. Не создавайте запись для Charlie: она понадобится для проверки сценария с отсутствующим ключом.
npx wrangler kv key list --binding PREFERENCES --local
Найдите четыре имени ключей. Для Alice и Bob должны отображаться метаданные ревизий 7 и 8. У двух остальных записей метаданных нет. Список показывает имена и метаданные, но не отображает каждое значение.
npx wrangler kv key get account:alice --binding PREFERENCES --local --text
Ожидаемый результат — {"theme":"dark","language":"en"}. Команда читает только значение, поэтому ревизия не входит в этот JSON-текст.
Теперь запишите те же четыре искусственные записи в облачное пространство имён этой лабораторной работы. Эти явные удалённые команды выполняют отдельные операции: локальная запись никогда не загружает данные в Cloudflare.
npx wrangler kv key put account:alice '{"theme":"dark","language":"en"}' --binding PREFERENCES --remote --metadata '{"revision":7}'
npx wrangler kv key put account:bob '{"theme":"light","language":"fr"}' --binding PREFERENCES --remote --metadata '{"revision":8}'
npx wrangler kv key put account:broken 'not-json' --binding PREFERENCES --remote
npx wrangler kv key put account:invalid '{"theme":"neon","language":"en"}' --binding PREFERENCES --remote
npx wrangler kv key list --binding PREFERENCES --remote
Подтвердите наличие тех же четырёх имён ключей и метаданных их ревизий. Это временные демонстрационные записи. Не изменяйте другие пространства имён.
Чтение настроек с безопасными значениями по умолчанию
На этом шаге вы напишете обработчик, который получает значение и метаданные вместе. Метод getWithMetadata() возвращает объект с полями value и metadata. Для отсутствующего ключа значение равно null. Метаданные также могут быть равны null, даже если значение существует.
Запишите этот обработчик. Документ here-document с разделителем в кавычках JS сохраняет код без изменений. Маршрут принимает короткое обозначение аккаунта в нижнем регистре и формирует отдельный ключ, например account:alice; он никогда не сохраняет аккаунт предыдущего запроса в глобальной переменной.
cat > src/index.js <<'JS'
function fallback(account, source) {
return Response.json({
account, theme: "light", language: "en", source, revision: null
});
}
export default {
async fetch(request, env) {
const match = new URL(request.url).pathname.match(/^\/preferences\/([a-z]{1,20})$/);
if (!match) return new Response("Not found", { status: 404 });
const account = match[1];
let entry;
try {
entry = await env.PREFERENCES.getWithMetadata(`account:${account}`, "text");
} catch {
return Response.json({ error: "Preferences temporarily unavailable" }, { status: 503 });
}
if (entry.value === null) return fallback(account, "missing");
let preferences;
try {
preferences = JSON.parse(entry.value);
} catch {
return fallback(account, "invalid");
}
if (!preferences || typeof preferences !== "object" || Array.isArray(preferences) ||
!["light", "dark"].includes(preferences.theme) ||
!["en", "fr"].includes(preferences.language)) {
return fallback(account, "invalid");
}
const revision = Number.isInteger(entry.metadata?.revision) && entry.metadata.revision > 0
? entry.metadata.revision : null;
return Response.json({
account, theme: preferences.theme, language: preferences.language,
source: "stored", revision
});
}
};
JS
Первый блок try/catch обрабатывает недоступность чтения из KV с помощью HTTP-статуса 503, который означает, что сервис временно недоступен. Он не выдаёт аккаунт за отсутствующий. Чтение в формате "text" с последующим разбором в отдельном try/catch позволяет обнаружить повреждённый JSON и не смешивать эту ситуацию со сбоем хранилища. Вариант чтения с параметром "json" может выполнить разбор автоматически, но в этом уроке две операции разделены, чтобы пути обработки ошибок были видны.
И для отсутствующих, и для недействительных настроек используются светлая тема и английский язык. Поле source объясняет причину применения значения по умолчанию. Если значение корректно, ответ использует только поддерживаемые поля темы и языка. Выражение entry.metadata?.revision безопасно обрабатывает отсутствие метаданных; положительная целая ревизия отображается, а в остальных случаях возвращается null. Эти значения по умолчанию позволяют использовать необязательные настройки отображения, но не заменяют аутентификацию или разрешения.
Запустите локальный Worker, сохраните идентификатор его процесса и дождитесь сообщения о готовности:
npx wrangler dev --local --ip 0.0.0.0 --port 8080 > local.log 2>&1 &
DEV_PID=$!
cat local.log
Фоновый процесс оставляет терминал свободным, а local.log содержит его вывод. Если запуск ещё не завершён, повторите команду просмотра журнала. Выполните запрос для каждого случая:
curl -i http://127.0.0.1:8080/preferences/alice
curl -i http://127.0.0.1:8080/preferences/bob
curl -i http://127.0.0.1:8080/preferences/charlie
curl -i http://127.0.0.1:8080/preferences/broken
curl -i http://127.0.0.1:8080/preferences/invalid
Все пять запросов должны вернуть HTTP 200 и JSON. Проверьте различия:
| Аккаунт | Тема | Язык | Источник | Ревизия |
|---|---|---|---|---|
| alice | dark | en | stored | 7 |
| bob | light | fr | stored | 8 |
| charlie | light | en | missing | null |
| broken | light | en | invalid | null |
| invalid | light | en | invalid | null |
Например, тело ответа для Alice выглядит так: {"account":"alice","theme":"dark","language":"en","source":"stored","revision":7}. Снова запросите Alice после Bob: настройки по-прежнему должны относиться к Alice. Не останавливайте локальный сервер до этапа очистки.
Проверка развёрнутого сервиса настроек
На этом шаге вы выполните те же запросы к облачному пространству имён. Отдельная облачная проверка подтверждает выбранный аккаунт, привязку развёрнутого пространства имён, сохранённые записи и фактические HTTP-ответы.
npx wrangler deploy
Проверьте в выводе сгенерированное имя Worker и привязку PREFERENCES. Скопируйте общедоступный адрес развёрнутого Worker в переменную ниже, заменив пример:
WORKER_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$WORKER_URL/preferences/alice"
curl -i "$WORKER_URL/preferences/bob"
curl -i "$WORKER_URL/preferences/charlie"
curl -i "$WORKER_URL/preferences/broken"
curl -i "$WORKER_URL/preferences/invalid"
Сравните все пять ответов с локальной таблицей. Для Alice и Bob должны сохраниться собственные настройки и метаданные ревизий; для Charlie и двух повреждённых записей должны использоваться описанные значения по умолчанию. Если недавно записанная запись пока не видна, подождите завершения распространения данных в KV и повторите запрос. Общедоступному имени хоста после первого развёртывания также может потребоваться некоторое время. Не считайте ошибку подключения ответом со значением по умолчанию.
В Dashboard выберите учебный аккаунт, откройте Storage & databases → Workers KV и найдите пространство имён labex-prefs-...-preferences этой лабораторной работы. Выберите KV Pairs, просмотрите четыре записи и нажмите View рядом с account:alice, чтобы сравнить значение JSON с выводом терминала. Здесь показаны ключи и значения; метаданные ревизии сравнивайте по предыдущему списку ключей Wrangler и ответу API. Уникальное имя пространства имён и идентификаторы будут отличаться от примера.

Общедоступная конечная точка предназначена только для демонстрации искусственных настроек отображения. Реальный закрытый сервис настроек должен сначала определить вызывающего пользователя и только затем решать, к какому ключу аккаунта ему разрешён доступ.
Удаление временных облачных ресурсов
На этом шаге вы удалите оба ресурса, пока Wrangler всё ещё авторизован. Пространство имён может существовать дольше Worker, поэтому удаление приложения само по себе не удаляет его данные.
Остановите процесс локальной разработки, запущенный в этом терминале:
kill "$DEV_PID"
Перед удалением проверьте сохранённые ссылки на ресурсы:
cat wrangler.jsonc
Убедитесь, что указаны имя Worker labex-prefs-... и идентификатор пространства имён PREFERENCES. Удалите Worker, выбранный этой конфигурацией:
npx wrangler delete
Если появится запрос подтверждения, проверьте, что показанное имя соответствует этой лабораторной работе, и подтвердите удаление с помощью y. Затем удалите только пространство имён, на которое ссылается PREFERENCES:
npx wrangler kv namespace delete --binding PREFERENCES
Перед подтверждением проверьте пространство имён в соответствующем запросе. Не изменяйте файл wrangler.jsonc, чтобы независимая проверка могла определить ресурсы, которые должны отсутствовать.
npx wrangler kv namespace list
Пространство имён этой лабораторной работы должно исчезнуть из списка, а другие пространства имён должны остаться. Обновите списки в Dashboard и убедитесь, что Worker и пространство имён этой лабораторной работы исчезли. Неудачный запрос или истёкшая авторизация не доказывают удаление. Выполните проверку этого шага до выхода из аккаунта, чтобы она могла просмотреть список ресурсов с действующей авторизацией.
Завершение авторизации виртуальной машины
На этом шаге вы отключите Wrangler после успешной проверки очистки. Выход из аккаунта удаляет сохранённые данные авторизации Wrangler для этой виртуальной машины; он не удаляет облачные ресурсы и не завершает обычный сеанс Dashboard в браузере.
npx wrangler logout
npx wrangler whoami --json
Убедитесь, что структурированный результат содержит "loggedIn": false. Эта команда без авторизации может завершиться с ненулевым кодом — в данном случае это ожидаемо. Если отображается только ошибка подключения без явного состояния аутентификации, повторите команду после восстановления соединения.
Оставшиеся локальные файлы и локальное состояние KV принадлежат временной виртуальной машине. Они не связаны с облачными ресурсами, которые вы уже удалили. Теперь лабораторную работу можно завершить.
Итоги
Вы сохранили структурированные настройки и метаданные ревизий в Workers KV, а затем прочитали их через привязку Worker. Настройки Alice и Bob оставались раздельными, а для отсутствующих, повреждённых и неподдерживаемых значений возвращались объяснимые значения по умолчанию. Вы также отличили сбой хранилища от отсутствующей записи, вместо того чтобы скрывать обе ситуации за одним и тем же ответом.
После сравнения локальных и облачных ответов вы удалили временные Worker и пространство имён, а затем вышли из аккаунта. В следующей лабораторной работе вы зададите временным уведомлениям срок действия в приложении и время истечения в KV.



