Импорт каталога перенаправлений

CloudflareBeginner
Практиковаться сейчас

Введение

Когда страницы сайта с документацией перемещаются, старые ссылки должны по-прежнему вести посетителей в нужное место. Перенаправление — это HTTP-ответ, который сообщает браузеру, что нужно запросить другой URL. В этой лабораторной работе KV будет хранить небольшой каталог, сопоставляющий старые пути с новыми путями документации.

Сначала вы проверите и провалидируете предоставленный набор данных JSON, затем импортируете его и прочитаете каталог по нескольким страницам. Пагинация означает запрос ограниченной порции результатов с использованием маркера продолжения для получения следующей порции. В конце вы измените один адрес назначения и удалите две записи, сохранив при этом несвязанную запись в том же пространстве имён. Это полезно при обслуживании набора настроек, когда нужно изменять не один ключ за раз.

Сначала завершите предыдущие практические работы с пошаговыми инструкциями по KV. Эта новая виртуальная машина содержит Node.js 22.22.0 и локальный для проекта Wrangler 4.131.1 в /home/labex/project/redirect-catalog. Подготовка создаёт пять тестовых перенаправлений, но не импортирует их и не создаёт облачные ресурсы. Используйте собственную учебную учётную запись с разрешениями account-read, Worker-write и KV-write. Достаточно одного временного Worker и одного пространства имён; для этого небольшого набора данных не нужны платное обновление или приобретённый домен. Открытый каталог содержит только примеры путей.

Подключение пространства имён перенаправлений

На этом шаге вы подключите отдельное пространство имён для небольшого каталога перенаправлений. Привязка ROUTES будет указывать на это пространство имён как в операциях из командной строки, так и в Worker. Каждая лабораторная работа использует собственные ресурсы, поэтому каталог не затронет предыдущие пространства имён.

Перейдите в подготовленный проект:

cd /home/labex/project/redirect-catalog

Один раз сгенерируйте уникальное имя. Команда openssl rand -hex 6 выводит случайный суффикс, а $(...) вставляет его в имя. Переменная оболочки сохранит это имя для следующих команд в данном терминале.

WORKER_NAME="labex-routes-$(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. На странице согласия также может отображаться разрешение фонового доступа. Вернитесь в терминал и дождитесь завершения входа.

Проверьте те же разрешения на чтение учётной записи и запись в Worker и KV, которые были введены в работе 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-routes" --update-config=false

В выводе появится новый идентификатор пространства имён. Скопируйте его, затем замените YOUR_ACCOUNT_ID и YOUR_NAMESPACE_ID в полной конфигурации ниже. Имя привязки ROUTES используется в вашем коде, а идентификатор указывает на реальный ресурс 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": "ROUTES", "id": "YOUR_NAMESPACE_ID" }
  ]
}
JSON
npx wrangler kv namespace list

Найдите пространство имён этой лабораторной работы и сравните его идентификатор с указанным в файле. Другие пространства имён могут присутствовать — не изменяйте их. Эта конфигурация определяет, какую учётную запись и какой ресурс должны использовать следующие команды. Привязка — это ссылка на пространство имён, а не копия его данных.

Проверка и импорт небольшого каталога

На этом шаге вы проверите набор данных до того, как одна команда запишет все его записи. Массовая операция экономит время на повторяющихся действиях, но также распространяет любую ошибку на все предоставленные данные. Сначала прочитайте подготовленный файл:

cat redirects.json

Каждый объект содержит key, например route:/old-start, и value, например /docs/start. Префикс route: группирует записи каталога; он является частью ключа, а не именем каталога. Адрес назначения — это путь на этом же сайте, а не произвольный внешний URL.

Создайте обычный скрипт проверки на Node.js. Он читает имя файла, проверяет массив и его поля, отклоняет дублирующиеся ключи и выводит количество только после успешной проверки всех записей. Объект Set запоминает уже встреченные ключи. Регулярные выражения ограничивают этот учебный набор простыми старыми путями и адресами документации; это правила данного приложения, а не ограничения KV.

cat > validate-redirects.mjs <<'JS'
import { readFile } from "node:fs/promises";

const filename = process.argv[2] ?? "redirects.json";
const entries = JSON.parse(await readFile(filename, "utf8"));
if (!Array.isArray(entries) || entries.length === 0 || entries.length > 20) {
  throw new Error("Use a non-empty teaching dataset of at most 20 entries.");
}
const seen = new Set();
for (const entry of entries) {
  if (!entry || typeof entry.key !== "string" || !/^route:\/old-[a-z-]+$/.test(entry.key)) {
    throw new Error("Every key must name an old route, such as route:/old-start.");
  }
  if (typeof entry.value !== "string" || !/^\/docs\/[a-z-]+$/.test(entry.value)) {
    throw new Error("Every destination must be a /docs/ path on this site.");
  }
  if (Object.keys(entry).some(key => !["key", "value"].includes(key))) {
    throw new Error("This dataset accepts only key and value fields.");
  }
  if (seen.has(entry.key)) throw new Error(`Duplicate key: ${entry.key}`);
  seen.add(entry.key);
}
console.log(`Validated ${entries.length} unique redirect entries.`);
JS
node validate-redirects.mjs redirects.json

Ожидаемый результат — Validated 5 unique redirect entries. Если проверка завершается ошибкой, исправьте файл до импорта. Отклонение дублирующихся ключей важно, потому что повторная запись того же ключа заменяет его значение.

Сначала создайте локальную несвязанную тестовую запись, затем импортируйте каталог. Эта запись поможет проверить, что последующее обслуживание каталога сохраняет другие данные.

npx wrangler kv key put system:owner labex-redirect-demo --binding ROUTES --local
npx wrangler kv bulk put redirects.json --binding ROUTES --local
npx wrangler kv key list --binding ROUTES --local

Ожидайте пять записей route: и запись system:owner. Команда bulk put записывает записи из файла; она не заменяет всё пространство имён и не удаляет ключи, отсутствующие в файле. Она также не гарантирует атомарное изменение, которое одновременно станет видимым везде.

Теперь импортируйте тот же проверенный набор данных в облачное пространство имён этой лабораторной работы:

npx wrangler kv key put system:owner labex-redirect-demo --binding ROUTES --remote
npx wrangler kv bulk put redirects.json --binding ROUTES --remote
npx wrangler kv key list --binding ROUTES --remote

Убедитесь, что присутствуют шесть ключей. Явные параметры назначения разделяют локальные операции и записи в облако. Выполните проверку этого шага до изменения любых записей.

Чтение всех страниц и обслуживание перенаправлений

На этом шаге вы создадите Worker, который перечисляет все ключи маршрутов и обслуживает их перенаправления. Один вызов KV list() может вернуть только часть коллекции. cursor — это маркер продолжения, предоставляемый KV; передавайте его обратно без изменений, чтобы запросить следующую часть.

Создайте этот обработчик. Намеренно небольшое значение limit: 2 делает пагинацию заметной даже при пяти записях. В рабочем коде обычно используют больший размер страницы; в этой лабораторной работе число записей ограничено двадцатью, поэтому цикл остаётся небольшим.

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    try {
      if (url.pathname === "/catalog") {
        const names = [];
        let cursor;
        let complete = false;
        let pages = 0;
        do {
          const page = await env.ROUTES.list({ prefix: "route:", limit: 2, cursor });
          names.push(...page.keys.map(key => key.name));
          pages += 1;
          complete = page.list_complete;
          cursor = complete ? undefined : page.cursor;
          if ((!complete && !cursor) || pages > 20) {
            return Response.json({ error: "Catalog could not be completed" }, { status: 503 });
          }
        } while (!complete);
        return Response.json({ keys: names, pages });
      }
      if (url.pathname.startsWith("/docs/")) {
        return new Response(`Example destination: ${url.pathname}`);
      }
      const target = await env.ROUTES.get(`route:${url.pathname}`);
      if (target === null) return new Response("Not found", { status: 404 });
      if (!/^\/docs\/[a-z-]+$/.test(target)) {
        return Response.json({ error: "Invalid redirect destination" }, { status: 500 });
      }
      return Response.redirect(new URL(target, url.origin).href, 302);
    } catch {
      return Response.json({ error: "Redirect storage unavailable" }, { status: 503 });
    }
  }
};
JS

Цикл do...while запрашивает как минимум одну страницу и продолжает работу, пока list_complete не станет равным true. На каждом запросе он сохраняет prefix: "route:", поэтому тестовая запись владельца не попадёт в каталог. Вызов names.push(...) добавляет имена ключей каждой страницы к результату.

Пустой массив keys не обязательно означает, что перечисление завершено: удалённые или истёкшие записи могут оставить страницу без возвращённых ключей, хотя впереди остаются другие страницы. Поэтому цикл использует list_complete, а не длину массива. Ограничение числа страниц и проверка отсутствующего курсора возвращают контролируемую ошибку, если этот небольшой пример не может завершить перечисление. См. раздел Перечисление и пагинация KV.

Для других путей Worker читает соответствующий ключ маршрута. Для отсутствующих маршрутов возвращается 404, а для поддерживаемого адреса назначения формируется ответ 302 с заголовком Location. Среда выполнения снова проверяет адрес назначения, чтобы ошибочно изменённое значение KV не могло перенаправить посетителей на другой сайт. Ответы /docs/ — это простые заглушки, показывающие путь назначения, а не полноценный сайт с документацией.

npx wrangler dev --local --ip 0.0.0.0 --port 8080 > local.log 2>&1 &
DEV_PID=$!
cat local.log

Дождитесь сообщения о готовности, затем просмотрите весь каталог:

curl -i http://127.0.0.1:8080/catalog

Ожидайте пять отсортированных ключей маршрутов и как минимум три страницы. Возможны дополнительные пустые страницы; важно, чтобы в результате присутствовал полный набор ключей без записи system:owner.

curl -i http://127.0.0.1:8080/old-start

Ожидайте HTTP-ответ 302 и заголовок Location: http://127.0.0.1:8080/docs/start. По умолчанию curl показывает ответ перенаправления, но не переходит по нему. Не изменяйте локальный набор данных, чтобы позже использовать его для сравнения.

Обновление выбранных маршрутов и сохранение других данных

На этом шаге вы измените облачный каталог, не заменяя его пространство имён. Новая стартовая страница — /docs/getting-started, а две временные страницы больше не должны выполнять перенаправление.

npx wrangler kv key put route:/old-start /docs/getting-started --binding ROUTES --remote

Запись выбранного ключа не затрагивает остальные маршруты. Для удаления нескольких ключей Wrangler принимает массив JSON с точными именами ключей. Перед удалением прочитайте небольшой список выводимых из эксплуатации ключей:

cat > retired-keys.json <<'JSON'
["route:/old-contact", "route:/old-event"]
JSON
cat retired-keys.json
npx wrangler kv bulk delete retired-keys.json --binding ROUTES --remote

Если появится запрос подтверждения, убедитесь, что привязка и указанная операция относятся к временному пространству имён этой лабораторной работы. В списке находятся только два ключа маршрутов; записи system:owner в нём нет.

npx wrangler kv key list --binding ROUTES --remote
npx wrangler kv key get system:owner --binding ROUTES --remote --text

Ожидайте три оставшихся маршрута и неизменённое значение labex-redirect-demo. Не запускайте исходный массовый импорт повторно: старые значения отменят обновление и восстановят удалённые ключи.

Разверните Worker, проверьте привязку ROUTES и скопируйте его фактический общедоступный адрес:

npx wrangler deploy
WORKER_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$WORKER_URL/catalog"

Сначала убедитесь, что /catalog возвращает HTTP 200 и ожидаемые ключи JSON. Если появилась страница ошибки Cloudflare, немного подождите и повторите запросы только для чтения. Удалённый маршрут считается проверенным лишь при HTTP 404 с телом приложения Not found; одного кода состояния недостаточно.

В каталоге должны остаться только route:/old-pricing, route:/old-start и route:/old-support. Проверьте изменённый и удалённые пути:

curl -i "$WORKER_URL/old-start"
curl -i "$WORKER_URL/old-contact"
curl -i "$WORKER_URL/old-event"

Ожидайте, что путь start перенаправляется на /docs/getting-started, а оба удалённых пути возвращают 404. Если новые облачные данные ещё не видны, подождите распространения изменений KV и повторите проверки, которые только читают данные. Ошибка подключения не означает, что удаление выполнено успешно.

curl -i http://127.0.0.1:8080/catalog

Локальная разработка по-прежнему показывает исходные пять маршрутов. Это различие подтверждает, что команды обслуживания работали с облачным хранилищем. В Dashboard выберите ту же учётную запись, откройте Storage & databases → Workers KV и найдите пространство имён этой лабораторной работы. Сравните его три записи маршрутов и сохранённую тестовую запись владельца с выводом команд. Этот контрольный этап предназначен только для чтения; имя и идентификатор созданного пространства имён зависят от текущего запуска.

Выберите KV Pairs, чтобы увидеть записи ниже. Нажмите Refresh, если пространство имён было открыто до завершения команд обслуживания.

Три сохранённых маршрута и неизменённая запись владельца

Удаление временных облачных ресурсов

На этом шаге вы удалите оба ресурса, пока Wrangler всё ещё авторизован. Пространство имён может существовать дольше Worker, поэтому удаление приложения само по себе не удаляет его данные.

Остановите процесс локальной разработки, запущенный в этом терминале:

kill "$DEV_PID"

Перед удалением проверьте сохранённые ссылки на ресурсы:

cat wrangler.jsonc

Убедитесь, что имя Worker имеет вид labex-routes-..., а в конфигурации указан идентификатор пространства имён ROUTES. Удалите Worker, выбранный этой конфигурацией:

npx wrangler delete

Если появится запрос подтверждения, проверьте, что отображаемое имя соответствует этой лабораторной работе, и подтвердите операцию, введя y. Затем удалите только пространство имён, указанное в ROUTES:

npx wrangler kv namespace delete --binding ROUTES

Перед подтверждением проверьте пространство имён в запросе. Не изменяйте wrangler.jsonc, чтобы независимая проверка могла определить ресурсы, которые должны отсутствовать.

npx wrangler kv namespace list

Пространство имён этой лабораторной работы должно отсутствовать, а несвязанные пространства имён должны сохраниться. Обновите списки в Dashboard и убедитесь, что Worker и пространство имён этой лабораторной работы исчезли. Ошибка запроса или истёкшая авторизация не доказывают, что удаление выполнено. Запустите проверку этого шага до выхода из системы, чтобы она могла просмотреть авторизованный список ресурсов.

Завершение авторизации виртуальной машины

На этом шаге вы отключите Wrangler после успешной проверки очистки. Выход из системы завершает сохранённую авторизацию Wrangler на этой виртуальной машине; он не удаляет облачные ресурсы и не завершает обычный сеанс Dashboard в браузере.

npx wrangler logout
npx wrangler whoami --json

Убедитесь, что структурированный результат содержит "loggedIn": false. Эта команда без авторизации может завершиться с ненулевым кодом выхода — в данном случае это ожидаемо. Если отображается только ошибка подключения без явного состояния аутентификации, повторите команду после восстановления соединения.

Оставшиеся локальные файлы и локальное состояние KV относятся к временной виртуальной машине. Они не связаны с облачными ресурсами, которые вы уже удалили. Теперь лабораторную работу можно завершить.

Итоги

Вы проверили небольшой набор данных перенаправлений перед массовой записью, явно разделили локальные и облачные назначения и обработали все страницы списка KV с заданным префиксом. Вы изменили один маршрут и удалили два точных ключа, сохранив несвязанную запись владельца. Ответы развёрнутого Worker подтвердили новый адрес назначения и отсутствие удалённых маршрутов, а локальный каталог сохранил исходные данные.

В конце вы удалили временные Worker и пространство имён и вышли из системы. Далее вы будете работать с чтением конфигурации, которое может временно возвращать более раннюю версию.