Умный фильтр в SEF-режиме — красивая штука с неприятным свойством: он разбирает любой набор сегментов в адресе как условия фильтра и отдаёт 200 OK практически на что угодно. Пустой список товаров, но код ответа — успешный.
Пока об этом не знают боты, всё нормально. Как только каталог начинают активно обходить, вы получаете бесконечное множество мусорных страниц в индексе, растущий кэш и потраченный краулинговый бюджет. Разберём, как научить каталог отличать осмысленный адрес от случайного.
Проблема
Фильтрация товаров в Битриксе создаёт множество URL-вариантов. Система может генерировать практически бесконечное число несуществующих URL с одинаковым содержимым, при этом все они возвращают статус 200 OK.
Как работает smart.filter
При использовании ЧПУ система формирует адреса вроде:
/catalog/plastikovye-konteynery/brand-is-tara_ru/Каждый сегмент интерпретируется как условие фильтра — значение свойства, диапазон, цена или бренд.
Источник проблемы
Можно генерировать бесконечные варианты:
/catalog/plastikovye-konteynery/prop_shirina-from-330/
/catalog/plastikovye-konteynery/prop_shirina-from-331/
/catalog/plastikovye-konteynery/prop_shirina-from-332/
...
/catalog/plastikovye-konteynery/prop_shirina-from-9999/Система также обрабатывает несуществующие свойства, случайные сегменты и поломанные комбинации, отдавая при этом 200 OK.
SEO-последствия
Проблемы без валидации:
- Дублирование контента с разными URL
- Размывание релевантности страниц
- Бесполезная трата краулингового бюджета
- Конкуренция между URL в поисковой выдаче
- Появление низкокачественного контента в индексе
Решение
Добавляем проверку валидности URL smart.filter до рендеринга страницы. Если адрес не соответствует допустимому формату, система переводит его на штатную 404-страницу.
Почему именно 404, а не noindex и не редирект.
noindex убирает страницу из индекса, но не мешает её сканировать: робот продолжит ходить по всем комбинациям, а значит краулинговый бюджет и нагрузка останутся. К тому же страница отработает целиком — PHP запустится, запросы к базе выполнятся, кэш создастся.
Редирект на раздел выглядит дружелюбно, но сообщает поисковику, что адрес существует и переехал. Для случайного набора сегментов это неверно, и робот будет возвращаться проверять.
404 — единственный честный ответ на «такого адреса нет». Робот исключает его из очереди, а при проверке до рендеринга страница даже не начинает выполняться.
Оговорка: проверять нужно до тяжёлой работы. 404 в конце обработки экономит индекс, но не экономит сервер, а под ботовой нагрузкой важно как раз второе.
Класс SmartFilterValidator
<?php
namespace Local\Catalog;
class SmartFilterValidator
{
private static array $validPropertyCodes = [];
private static ?int $catalogIblockId = null;
public static function handleCatalogSmartFilterRequest(): void
{
$requestPath = self::getRequestPath();
// Проверяем, что это URL каталога с фильтром
if (!preg_match('~^/catalog/[^/]+/(.+?)/?$~u', $requestPath, $matches)) {
return;
}
$tail = trim($matches[1], '/');
if ($tail === '') {
return;
}
$segments = self::splitSmartFilterSegments($tail);
// Если есть признаки smart.filter и они невалидны — 404
if (self::hasSmartFilterHints($segments) && !self::validateSmartFilterSegments($segments)) {
self::processSmartFilter404();
}
}
private static function splitSmartFilterSegments(string $tail): array
{
return array_filter(explode('/', $tail));
}
private static function hasSmartFilterHints(array $segments): bool
{
foreach ($segments as $segment) {
if (self::isSmartFilterProp($segment)) {
return true;
}
}
return false;
}
public static function isSmartFilterProp(string $property): bool
{
// Проверяем формат свойства smart.filter
return preg_match('/(?:-is-|^prop_[^\/]+|^price-[^\/]+)/u', $property) > 0;
}
private static function validateSmartFilterSegments(array $segments): bool
{
self::loadValidPropertyCodes();
foreach ($segments as $segment) {
if (!self::isValidSegment($segment)) {
return false;
}
}
return true;
}
private static function isValidSegment(string $segment): bool
{
// Формат: property_code-is-value или prop_code-from-N-to-M
// Проверка свойств типа brand-is-value
if (preg_match('/^([a-z0-9_]+)-is-(.+)$/i', $segment, $matches)) {
$propertyCode = $matches[1];
return in_array(strtoupper($propertyCode), self::$validPropertyCodes);
}
// Проверка свойств типа prop_code-from-N
if (preg_match('/^prop_([a-z0-9_]+)-(from|to)-(\d+)$/i', $segment, $matches)) {
$propertyCode = $matches[1];
return in_array(strtoupper($propertyCode), self::$validPropertyCodes);
}
// Проверка цен
if (preg_match('/^price-([a-z]+)-(from|to)-(\d+)$/i', $segment)) {
return true;
}
return false;
}
private static function loadValidPropertyCodes(): void
{
if (!empty(self::$validPropertyCodes)) {
return;
}
$catalogIblockId = self::getCatalogIblockId();
$properties = \CIBlockProperty::GetList(
[],
[
'IBLOCK_ID' => $catalogIblockId,
'ACTIVE' => 'Y',
]
);
while ($prop = $properties->Fetch()) {
self::$validPropertyCodes[] = strtoupper($prop['CODE']);
}
}
private static function processSmartFilter404(): void
{
if (!defined('ERROR_404')) {
define('ERROR_404', 'Y');
}
\Bitrix\Iblock\Component\Tools::process404(
'',
true, // показать 404
true, // включить в статистику
true, // записать в лог
'/404.php'
);
die();
}
private static function getRequestPath(): string
{
return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?? '';
}
}Подключение валидатора
В init.php:
<?php
use Bitrix\Main\EventManager;
$eventManager = EventManager::getInstance();
$eventManager->addEventHandler(
'main',
'OnBeforeProlog',
function () {
\Local\Catalog\SmartFilterValidator::handleCatalogSmartFilterRequest();
}
);Важность корректной 404-обработки
Почему используем встроенный механизм Битрикса?
Метод \Bitrix\Iblock\Component\Tools::process404() корректно:
- Отдаёт реальный HTTP 404
- Рендерит штатную страницу ошибки
- Не ломает шаблон и заголовки
- Записывает событие в статистику
Главный риск внедрения — отдать 404 на живых страницах. Валидатор слишком строгий или не знает про свойство, добавленное после его написания, — и раздел каталога, который приносил заказы, начинает отвечать «страница не найдена». Из индекса он вылетит быстро, вернётся долго.
Поэтому порядок внедрения такой:
- Сначала режим наблюдения. Валидатор работает, но вместо
process404()пишет в лог «признал бы невалидным такой-то URL». День-два логов покажут, что реально попадает под правила. - Просмотреть лог глазами. В нём не должно быть адресов из sitemap, из внутренних ссылок и из отчётов Search Console по страницам с трафиком.
- Только потом включать 404 — и следить за отчётом «Страницы» в панели вебмастера ближайшие недели.
Проверка после включения делается быстро:
# Валидный раздел — должен быть 200
curl -o /dev/null -s -w "%{http_code}\n" https://site.ru/catalog/konteynery/
# Валидный фильтр — 200
curl -o /dev/null -s -w "%{http_code}\n" https://site.ru/catalog/konteynery/filter/brand-is-tara_ru/apply/
# Мусор — должен быть 404
curl -o /dev/null -s -w "%{http_code}\n" https://site.ru/catalog/konteynery/filter/prop_nesushchestvuet-from-777/apply/Результаты
После внедрения решения:
| Метрика | До | После |
|---|---|---|
| Ответ на невалидные URL | 200 OK | 404 |
| Количество дублей в индексе | Растёт | Стабильно |
| Краулинговый бюджет | Тратится впустую | Используется эффективно |
| Рост кэша | Неконтролируемый | Минимальный |
Вывод
Без собственной валидации умный фильтр становится генератором мусорных страниц, отдающих 200 OK. Проверка перед рендером и честная 404 решают сразу три задачи: чистый индекс, сэкономленный краулинговый бюджет и остановленный рост кэша.
Что важно помнить при внедрении:
Проверка должна стоять до тяжёлой работы. Смысл не только в коде ответа, но и в том, чтобы под ботовой нагрузкой не выполнялись запросы к базе.
Валидатор — это белый список. Разрешено то, что вы явно описали: существующие свойства, допустимые значения, разумные диапазоны. Попытка перечислить «плохие» варианты обречена — их бесконечно много, в том и была исходная проблема.
Список значений нужно обновлять вместе с каталогом. Новое свойство в умном фильтре, о котором валидатор не знает, — это 404 на работающих страницах. Берите допустимые значения из настроек фильтра и свойств инфоблока, а не из захардкоженного массива.
Это половина решения. Вторая половина — ограничение кэширования для таких URL и лимит частоты для ботов. Вместе они закрывают вопрос; по отдельности каждая мера оставляет часть нагрузки.
Комментарии
Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.