Перейти к содержанию

Защита прежних адресов

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

В этом уроке добавим небольшую учебную модель таких адресов. Полные состояния находятся в lesson-20/start и expected архива продолжения. Запросы направлены только на 127.0.0.1:4407. Маршрут напоминает прежнюю схему ProfessorWeb, но содержит вымышленный материал лаборатории; настоящий сайт и его защищённые страницы не запрашиваются. Тесты и сервер сейчас не запускались.

Адрес является частью договорённости

Зададим /my/html/html5/level1/1_1.php как адрес учебной статьи «Основы HTML». Сервер возвращает 200, HTML, один H1 и текст внутри article. Суффикс .php здесь часть пути. Node не исполняет PHP, а находит фиксированный маршрут в коде. Поэтому сохранение имени URL не требует, чтобы новая реализация использовала тот же язык исполнения.

Отдельный /old-html.php считаем известным дублем и направляем через 301 на сохранённую статью. Это решение относится только к этому явно заданному дублю. Важный основной адрес остаётся 200; мы не перенаправляем все старые страницы на главную или каталог. Для отсутствующего пути возвращаем настоящую 404 с заголовком «Страница не найдена».

Путь лаборатории Ожидаемый ответ Значение
/my/html/html5/level1/1_1.php 200 Сохранённая статья
/old-html.php 301 Один известный дубль
/my/html/html5/level1/missing.php 404 Отсутствующий материал
/my/html/html5/level1/1_1.php/extra 404 Ложное продолжение имени файла

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

Статус до автоматического перехода

API-клиент может автоматически следовать редиректу. Тогда запрос к /old-html.php покажет итоговую 200, скрыв первоначальную 301. Для проверки первой части договорённости отключим переходы:

const legacy = '/my/html/html5/level1/1_1.php';
const response = await request.get(legacy, { maxRedirects: 0 });
expect(response.status()).toBe(200);
expect(new URL(response.url()).pathname).toBe(legacy);
expect(response.headers()['content-type']).toContain('text/html');

Утверждение адреса уточняет, что мы получили ответ по исходному пути. Затем браузер открывает тот же URL, и сценарий связывает транспорт с материалом. При этом request не использует подмену page.route(): проверяется настоящий ответ учебного Node-сервера, когда лабораторию разрешат выполнить.

Настройка maxRedirects и свойства ответа описаны в APIRequestContext. Для чтения исходников важно понимать её назначение: мы выбираем наблюдение первого ответа. Это не отключает поведение браузера в следующей части сценария и не изменяет маршруты сервера.

Правильная страница после открытия

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

const navigation = await page.goto(legacy);
expect(navigation.status()).toBe(200);
await expect(page).toHaveURL(`http://127.0.0.1:4407${legacy}`);
await expect(page.getByRole('heading', {
  name: 'Основы HTML', level: 1, exact: true
})).toBeVisible();
await expect(page.locator('article')).toContainText('Учебный материал c001');

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

Мы не сравниваем всю HTML-оболочку побайтно. Общий хедер, футер и пагинация могут изменяться согласованно, пока материал остаётся тем же. Что считать допустимым изменением, задаётся отдельной договорённостью переноса. Этот короткий сценарий демонстрирует один способ наблюдения, а не заменяет реестр всех важных страниц.

Дубль и ошибка имеют разные признаки

Для /old-html.php сначала проверяется 301 и точный Location. Затем браузер следует переходу, и ожидается сохранённый URL с правильным H1. Если Location начнёт вести на каталог, статус редиректа останется верным, но адрес и содержание конечной страницы не совпадут с договорённостью.

Для отсутствующих путей проверяется 404 в API и в ответе page.goto(). Браузер при этом может нормально показать HTML ошибки: видимая страница сама по себе не означает статус 200. Именно сочетание статуса и заголовка отличает правильную ошибку от мягкой 404, когда сервер сообщает успех и рисует текст о несуществующем материале.

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

Совпадение пути в лаборатории чувствительно к точному написанию. Регистр, дополнительный сегмент и выбранное имя задают маршрутизацию; мы не вводим автоматические догадки о похожей странице. Параметры запроса сейчас не участвуют в выборе материала: сервер сравнивает pathname. Это ограничение нужно отметить, чтобы набор не выдавался за исследование всех query-вариантов.

В большом реестре важно сохранить и исходный вариант адреса, и принятое правило для дубля. Массовое приведение регистра или удаление параметров может объединить разные ресурсы. Поэтому нормализация должна следовать данным сайта и проверенному назначению параметров. Наш маленький набор не выполняет такую нормализацию и не изменяет исходные permalink материалов ProfessorWeb.

От четырёх условий к реестру сайта

В рабочем проекте список важных путей сохраняют как данные. Для каждого указывают ожидаемый статус, конечный адрес при допустимом переходе и признак материала. Важно различать сохранённую страницу, согласованный дубль и действительно отсутствующую страницу. Иначе массовое правило «любой ответ без ошибки» пропустит потерю учебной библиотеки.

В ProfessorWeb такой реестр связан со старой структурой и страницами с поисковым трафиком. Здесь мы не пересчитываем его и не объявляем все адреса проверенными. Чтобы применить приём к тысячам страниц, понадобятся исходный инвентарь, ограничения нагрузки, выбранная среда и отдельное разрешённое выполнение. Большое число строк в матрице само по себе ещё не является свидетельством их проверки.

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