Умный фильтр в SEF-режиме — красивая штука с неприятным свойством: он разбирает любой набор сегментов в адресе как условия фильтра и отдаёт 200 OK практически на что угодно. Пустой список товаров, но код ответа — успешный.
Пока об этом не знают боты, всё нормально. Как только каталог начинают активно обходить, вы получаете бесконечное множество мусорных страниц в индексе, растущий кэш и потраченный краулинговый бюджет. Разберём, как научить каталог отличать осмысленный адрес от случайного.
Почему smart.filter отдаёт 200 на несуществующих URL
Фильтрация товаров в Битриксе создаёт множество 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 в поисковой выдаче
- Появление низкокачественного контента в индексе
Как научить каталог отдавать 404 на мусорных адресах
Добавляем проверку валидности 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 и лимит частоты для ботов. Вместе они закрывают вопрос; по отдельности каждая мера оставляет часть нагрузки.
Частые вопросы
Почему smart.filter отдаёт 200 на несуществующих адресах?
Потому что в SEF-режиме он разбирает каждый сегмент адреса как условие фильтра — значение свойства, диапазон, цену или бренд — и не проверяет, осмысленна ли комбинация. Несуществующие свойства, случайные сегменты и поломанные комбинации обрабатываются так же: страница отдаётся с кодом 200, просто список товаров пустой. Вариантов таких адресов можно сгенерировать практически бесконечно.
Чем мусорные URL фильтра вредят SEO?
Дублированием контента по разным адресам, размыванием релевантности страниц, бесполезной тратой краулингового бюджета, конкуренцией URL между собой в выдаче и появлением низкокачественного контента в индексе. Плюс чисто техническая нагрузка: каждый такой адрес порождает свой кэш, и директория кэша растёт неограниченно.
Почему 404, а не noindex и не редирект?
noindex убирает страницу из индекса, но не мешает её сканировать: робот продолжит ходить по всем комбинациям, значит краулинговый бюджет и нагрузка останутся, а страница отработает целиком — PHP запустится, запросы к базе выполнятся, кэш создастся. Редирект на раздел выглядит дружелюбно, но сообщает поисковику, что адрес существует и переехал, и для случайного набора сегментов это неверно — робот будет возвращаться проверять. 404 — единственный честный ответ на «такого адреса нет»: робот исключает его из очереди.
Когда именно проверять валидность адреса фильтра?
До тяжёлой работы, а не в конце обработки. Ответ 404 в конце экономит индекс, но не экономит сервер, а под ботовой нагрузкой важно как раз второе. Проверку вешают на раннее событие в init.php, и при неудаче вызывают Bitrix\Iblock\Component\Tools::process404 — встроенный механизм корректно отдаёт реальный код 404, рендерит штатную страницу ошибки, не ломает шаблон и заголовки и записывает событие в статистику.
Чем рискует внедрение валидатора smart.filter?
Тем, что 404 уйдёт на живых страницах. Валидатор слишком строгий или не знает про свойство, добавленное после его написания, — и раздел каталога, который приносил заказы, начинает отвечать «страница не найдена». Из индекса он вылетит быстро, а вернётся долго.
Как безопасно внедрить проверку валидности?
В три шага. Сначала режим наблюдения: валидатор работает, но вместо отдачи 404 пишет в лог, какой адрес он признал бы невалидным. Затем просмотреть лог глазами — в нём не должно быть адресов из sitemap, из внутренних ссылок и из отчётов Search Console по страницам с трафиком. И только потом включать 404, следя за отчётом «Страницы» в панели вебмастера ближайшие недели.