AJAX в Битрикс — это не одна технология, а несколько слоёв: встроенный режим компонента, ручные запросы к ajax.php и полноценные контроллеры на базе \Bitrix\Main\Engine\Controller. Разберём, когда какой подход уместен и как не сломать кэш.
Встроенный AJAX_MODE компонента 2.0
Многие типовые компоненты (bitrix:news.list, bitrix:catalog.section) поддерживают встроенный AJAX через группу параметров AJAX_MODE. При включении ядро само перехватывает переход по постраничной навигации или ссылке и подгружает только область компонента, не перезагружая страницу.
Ключевые параметры вызова:
AJAX_MODE—Y/N, общий переключатель;AJAX_OPTION_JUMP— прокрутка к началу блока после загрузки;AJAX_OPTION_HISTORY— работа с историей браузера (pushState);AJAX_OPTION_ADDITIONAL— уникальный ключ, если на странице несколько одинаковых компонентов.
Технически область компонента оборачивается в контейнер с идентификатором вида comp_<хэш>, а ядро подключает main.core для перехвата кликов. Это самый быстрый путь, если готовый функционал вас устраивает.
Почему важен component_epilog.php
При AJAX-перезагрузке ядро возвращает только HTML области компонента, но не выполняет заново весь код компонента — результат берётся из кэша. Единственный файл шаблона, который выполняется всегда, минуя кэш, — это component_epilog.php.
Поэтому регистрацию заголовков страницы, хлебных крошек и подключение ассетов при AJAX-навигации нужно делать именно в эпилоге:
<?php
use Bitrix\Main\Page\Asset;
// component_epilog.php — выполняется и при обычной загрузке, и при AJAX
$APPLICATION->AddChainItem($arResult['NAME'], $arResult['SECTION_PAGE_URL']);
Asset::getInstance()->addCss('/local/templates/main/css/catalog.css');
?>
template.php и result_modifier.php попадают в кэш. component_epilog.php — нет. Данные для эпилога передают через $this->__component->arResult из component.php.Ручной AJAX через ajaxComponentId
Когда встроенного режима мало, но переписывать компонент не хочется, применяют «половинчатый» приём: компонент рендерится целиком, а на клиенте перезапрашивается только его область по идентификатору. В шаблоне доступна переменная $this->ajaxComponentId — уникальный ID экземпляра компонента.
На клиенте вызывается запрос с параметром bxajaxid, равным этому ID. Ядро распознаёт его в \CMain::IsAjaxRequest() и рендерит страницу так, чтобы вывелась только нужная область:
BX.ajax.runComponentAction — здесь не подходит; используем BX.ajax:
BX.ajax.insertToNode(
window.location.href + '?bxajaxid=' + ajaxId,
'component-container'
);
Этот способ проще контроллеров, но тянет за собой инициализацию всей страницы, поэтому для частых запросов он тяжеловат.
Контроллеры компонента (D7)
Современный и рекомендуемый способ — action-контроллеры. В классе компонента реализуют интерфейс \Bitrix\Main\Engine\Contract\Controllerable и метод configureActions(). Тогда действия компонента доступны по единому эндпоинту /bitrix/services/main/ajax.php.
class MyListComponent extends CBitrixComponent implements \Bitrix\Main\Engine\Contract\Controllerable
{
public function configureActions()
{
return [
'addToFavorites' => [
'prefilters' => [new \Bitrix\Main\Engine\ActionFilter\Csrf()],
],
];
}
public function addToFavoritesAction(int $id): array
{
// логика
return ['success' => true, 'id' => $id];
}
}
Метод-обработчик обязан иметь суффикс Action. Возврат массива автоматически сериализуется в JSON. На клиенте вызов лаконичен:
BX.ajax.runComponentAction('vendor:my.list', 'addToFavorites', {
mode: 'class',
data: { id: 42 }
}).then(function(response) {
console.log(response.data);
});
Префильтры, CSRF и безопасность
Главное преимущество контроллеров — встроенные фильтры (ActionFilter), которые снимают рутину проверок. Наиболее востребованные:
| Фильтр | Назначение |
|---|---|
ActionFilter\Csrf | Проверка sessid-токена от подделки запросов |
ActionFilter\Authentication | Требует авторизованного пользователя |
ActionFilter\HttpMethod | Ограничивает метод (только POST и т. п.) |
ActionFilter\ContentType | Проверка Content-Type запроса |
check_bitrix_sessid() ваш обработчик уязвим. При использовании BX.ajax.runComponentAction токен подставляется автоматически, при ручном fetch — передавайте sessid сами.Ошибки удобно возвращать через исключения: выброшенное \Bitrix\Main\SystemException ядро само упакует в response.errors, а на клиенте они окажутся в .catch().
AJAX, кэш и композитный сайт
AJAX и кэширование тесно связаны. Если компонент выводит персональные данные (корзина, избранное) на закэшированной или композитной странице, эти блоки нужно догружать отдельным AJAX-запросом уже после отдачи статики.
- Композитный кэш отдаёт «замороженный» HTML; динамические области помечают через
BX.readyи подгружают контроллером; - для действий, меняющих данные, используйте
POST—GET-запросы могут кэшироваться прокси и браузером; - после успешного action, изменившего контент, при необходимости сбрасывайте тегированный кэш через
\Bitrix\Main\Data\TaggedCache.
Такое разделение даёт быструю отдачу страницы и корректные персональные блоки без гонки за инвалидацией кэша.
Итог
Для типовых сценариев подойдёт встроенный AJAX_MODE, для точечной перезагрузки области — приём с ajaxComponentId, а для полноценной бизнес-логики — action-контроллеры на \Bitrix\Main\Engine\Controller с префильтрами. Не забывайте про component_epilog.php для того, что должно выполняться мимо кэша, и про CSRF-защиту.
Когда AJAX-логика разрастается до отдельного API или упирается в производительность на композитном сайте, мы в B2Bsite проектируем контроллеры, эндпоинты и кэш-стратегию так, чтобы интерфейс оставался отзывчивым под реальной нагрузкой.
Частые вопросы
Чем runComponentAction отличается от runAction?
runComponentAction вызывает action внутри класса компонента, а runAction обращается к контроллеру модуля. Для логики, привязанной к конкретному компоненту, используют первый вариант, для переиспользуемых серверных методов — второй.
Почему при AJAX-навигации не обновляется title страницы?
Потому что тело компонента берётся из кэша, а установка заголовка обычно живёт в component.php. Переносите AddChainItem и SetTitle в component_epilog.php, который выполняется всегда.
Нужно ли вручную проверять sessid в action-методе?
Если вы подключили фильтр ActionFilter\Csrf в configureActions, проверка выполняется автоматически. При ручных запросах через fetch без этого фильтра токен нужно проверять самому.
Как вернуть ошибку из action, чтобы она попала в .catch на клиенте?
Выбросьте \Bitrix\Main\SystemException внутри метода. Ядро упакует сообщение в массив response.errors, и промис на клиенте перейдёт в состояние rejected.
Работает ли встроенный AJAX_MODE с постраничной навигацией?
Да, это его основной сценарий. При включённом AJAX_OPTION_HISTORY переходы по страницам подменяют URL через pushState и подгружают только область компонента.
Можно ли использовать GET для action-запросов?
Технически да, но для операций, меняющих данные, всегда используйте POST. GET-ответы могут кэшироваться браузером и прокси, что приведёт к некорректному поведению.
Как отдавать персональные данные на композитной странице?
Статику отдаёт композитный кэш, а персональные блоки (корзина, избранное) догружаются отдельным AJAX-запросом через контроллер после события BX.ready.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.