В 2010 году на этом блоге был пост про AJAX в Битрикс с CPHttpRequest и jsAjaxUtil. С тех пор в платформе появился D7, а сам старый API остался — но для новых задач его выбирать не стоит. На стороне сервера актуальны два способа: через контроллер компонента или через свой обработчик. На клиенте к обоим можно обращаться чем угодно — обычным fetch, jQuery или из Vue-компонента, бэкенд от этого не меняется.
Между CPHttpRequest и fetch в истории API был ещё промежуточный BX.ajax({ url, method, data, onsuccess, onfailure }) — низкоуровневая обёртка над XMLHttpRequest, без промисов и без автоматического CSRF. Она рабочая и встречается в старом коде, но в новых проектах проще сразу fetch или BX.ajax.runComponentAction — добавлять BX.ajax в новый код незачем.
Способ 1: BX.ajax.runComponentAction — если работа идёт через компонент
Штатный способ D7. Компонент реализует интерфейс Controllerable, действия (actions) описываются методом configureActions(), а вызов идёт через BX.ajax.runComponentAction — Битрикс сам подставляет CSRF-токен, а если тот истёк — получает новый и повторяет запрос.
class.php компонента
<?php
use Bitrix\Main\Engine\ActionFilter;
use Bitrix\Main\Engine\Contract\Controllerable;
class ExampleComponent extends \CBitrixComponent implements Controllerable
{
public function configureActions(): array
{
return [
'loadMore' => [
'prefilters' => [
new ActionFilter\Csrf(),
],
],
];
}
public function loadMoreAction(int $page): array
{
return [
'items' => $this->getItems($page),
];
}
public function executeComponent()
{
$this->includeComponentTemplate();
}
}JavaScript
BX.ajax.runComponentAction('vendor:example', 'loadMore', {
mode: 'class',
data: { page: 2 },
}).then(function (response) {
console.log(response.data.items);
}, function (response) {
console.error(response.errors);
});response.data приходит уже разобранным JSON, ошибки — отдельным полем errors, промис завершается успешно (resolve) только при status: 'success', иначе — reject. Для действий модуля (не привязанных к компоненту) есть аналогичный BX.ajax.runAction('module.action', {...}).
Плюс подхода — CSRF, обработка ошибок и связь action → метод контроллера уже сделаны платформой. Минус — годится только если данные и так отдаёт компонент; для произвольного обработчика вне компонентной модели это лишний код.
Способ 2: свой обработчик на fetch — если компонент не нужен
Для служебного обработчика вне компонентов (кастомная форма, счётчик, интеграция) поднимать под него компонент избыточно. Актуальная версия того, что раньше делал CPHttpRequest, — обычный fetch к своему PHP-файлу.
Серверный обработчик
<?php
define('STOP_STATISTICS', true);
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php');
if (!check_bitrix_sessid()) {
(new \Bitrix\Main\Engine\Response\Json(['error' => 'bad sessid'], JSON_UNESCAPED_UNICODE))->send();
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_after.php');
exit;
}
$param = htmlspecialchars($_POST['param'] ?? '', ENT_QUOTES, 'UTF-8');
(new \Bitrix\Main\Engine\Response\Json(['param' => $param], JSON_UNESCAPED_UNICODE))->send();
require($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_after.php');STOP_STATISTICS по-прежнему исключает запрос из счётчика статистики Битрикс — из констант 2010 года она не единственная, что дожила до наших дней, но самая частая в AJAX-обработчиках. \Bitrix\Main\Engine\Response\Json сам ставит заголовок Content-Type: application/json; charset=UTF-8 — кодировка windows-1251 из старого поста для новых проектов не нужна, D7 работает в UTF-8. После send() важно ничего больше не выводить — epilog_after.php в конце обязателен (закрывает сессию, финализирует буфер), а не echo/var_dump для отладки.
JavaScript
fetch('/ajax/example.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
param: 'test_param',
sessid: BX.bitrix_sessid(),
}),
})
.then((r) => {
if (!r.ok) {
throw new Error(`HTTP ${r.status}`);
}
return r.json();
})
.then((data) => {
document.getElementById('container').innerHTML = data.param;
});fetch не отклоняет промис на HTTP-ошибках (404, 500) — только на сетевой сбой, поэтому r.ok нужно проверять руками, иначе .json() на пустом теле ответа падает с непонятной ошибкой. BX.bitrix_sessid() отдаёт текущий CSRF-токен на клиенте — без него check_bitrix_sessid() на сервере вернёт false. Индикатор загрузки делаем своей вёрсткой — jsAjaxUtil.ShowLocalWaitWindow() из старого поста тоже устарел вместе с остальным API.
Для загрузки файла тем же способом вместо URLSearchParams — FormData, Content-Type при этом не указываем, браузер сам подставит правильный boundary:
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('sessid', BX.bitrix_sessid());
fetch('/ajax/example.php', {
method: 'POST',
body: formData,
}).then((r) => r.json());Тот же $_POST['sessid'] и $_FILES['file'] на сервере — check_bitrix_sessid() из примера выше работает без изменений, файл читается штатным $_FILES. BX.ajax.runComponentAction тоже принимает FormData в data — для action-метода компонента ничего дополнительно готовить не нужно.
jQuery — если библиотека уже в проекте
Для старых проектов, где jQuery уже подключён, $.ajax — прямая замена CPHttpRequest/fetch из способа 2. Обращается к тому же обработчику, серверная часть не меняется:
$.ajax({
url: '/ajax/example.php',
type: 'POST',
data: {
param: 'test_param',
sessid: BX.bitrix_sessid(),
},
success: function (data) {
$('#container').html(data.param);
},
error: function (xhr) {
console.error(xhr.responseText);
},
});Разница с fetch — только синтаксис. Для BX.ajax.runComponentAction (способ 1) jQuery не нужен вообще — это уже готовый промис, оборачивать его в $.ajax незачем.
Vue-компонент — та же логика, реактивный клиент
Если фронтенд собирается на Vue (виджет, форма, личный кабинет) внутри шаблона компонента Bitrix, AJAX-логика та же самая — просто вызывается из метода компонента, а не напрямую из обработчика клика.
Composition API (актуальный вариант, Vue 3)
<script setup>
import { ref, onMounted } from 'vue';
const items = ref([]);
const loading = ref(false);
async function loadMore(page) {
loading.value = true;
const response = await BX.ajax.runComponentAction('vendor:example', 'loadMore', {
mode: 'class',
data: { page },
});
items.value.push(...response.data.items);
loading.value = false;
}
onMounted(() => loadMore(1));
</script>
<template>
<ul>
<li v-for="item in items" :key="item.id">{{ item.title }}</li>
</ul>
<button :disabled="loading" @click="loadMore(2)">Ещё</button>
</template>BX.ajax.runComponentAction возвращает промис — в async-методе Vue его достаточно await-нуть. Для этих двух примеров axios не требуется — в большом SPA со своим API-слоем он всё ещё может быть оправдан, но конкретно для контроллера компонента или обработчика на fetch это лишняя зависимость.
Options API (старый код на Vue 2 или ранний Vue 3)
Та же логика без <script setup>:
export default {
data() {
return { items: [], loading: false };
},
methods: {
async loadMore(page) {
this.loading = true;
const response = await BX.ajax.runComponentAction('vendor:example', 'loadMore', {
mode: 'class',
data: { page },
});
this.items.push(...response.data.items);
this.loading = false;
},
},
mounted() {
this.loadMore(1);
},
};Что выбрать
- Данные и так приходят из компонента (каталог, список, фильтр) —
BX.ajax.runComponentAction, CSRF и разбор ответа не пишутся руками. - Нужен отдельный служебный обработчик без привязки к компоненту — свой на
fetch, CSRF черезcheck_bitrix_sessid()/BX.bitrix_sessid()проверяется вручную. - jQuery уже в проекте —
$.ajaxвместоfetchдля своего обработчика; для контроллера компонента без разницы,BX.ajax.runComponentActionи так возвращает промис. - Фронтенд на Vue — тот же
BX.ajax.runComponentAction/fetch, просто вызванный из метода компонента (Composition API — актуальный вариант, Options API — для старого кода). CPHttpRequestиjsAjaxUtil— только если поддерживается старый проект, где они уже есть; в новый код их добавлять незачем.
Независимо от способа: если запрос меняет данные — метод POST, GET оставляем только для чтения.
Если AJAX-запрос не срабатывает и непонятно почему — отдельный старый пост про отладку AJAX в админке Битрикс.
