Защита прежних адресов
Когда старый сайт перерабатывают, главная страница может выглядеть правильно, а важный прежний адрес уже возвращать не тот материал. В 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 и правилами индексации именно выбранной среды.