Bitrix\Main\Engine\Controller — штатный способ обрабатывать AJAX-запросы
в новом ядре 1С-Битрикс. Вместо самописного файла с подключением пролога вы описываете
класс с методами-действиями, а ядро берёт на себя проверку токена, разбор параметров
и формирование ответа.
Разберём устройство контроллера, систему фильтров, возврат ошибок и способы вызова с фронтенда. Обзор остальных подходов к AJAX есть в статье AJAX в Битрикс.
Минимальный контроллер
<?php // /local/php_interface/classes/Controller/Catalog.php
namespace Project\Controller;
use Bitrix\Main\Engine\Controller;
class Catalog extends Controller
{
public function getItemAction(int $id): array
{
return [
'id' => $id,
'name' => 'Товар ' . $id,
];
}
}
Два правила именования, без которых ничего не заработает:
- метод-действие обязан заканчиваться на
Action; - в вызове с фронтенда суффикс
Actionне указывается.
Регистрируем класс для автозагрузки в init.php:
<?php
use Bitrix\Main\Loader;
Loader::registerAutoLoadClasses(null, [
'Project\\Controller\\Catalog' => '/local/php_interface/classes/Controller/Catalog.php',
]);
Параметры действия
Параметры приходят обычными аргументами метода — разбирать $_POST не нужно.
Типы приводятся автоматически:
<?php
public function searchAction(string $query, int $limit = 10, bool $exact = false): array
{
// $query, $limit и $exact уже нужного типа
return ['found' => []];
}
Если обязательный параметр не передан, ядро само вернёт ошибку — до тела метода выполнение не дойдёт. Значения по умолчанию работают как в обычном PHP.
Нужна помощь с Битрикс?
Фильтры
Фильтры — проверки, выполняемые до действия. Именно они закрывают то, что в самописных обработчиках приходится писать руками.
<?php
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Engine\ActionFilter;
class Catalog extends Controller
{
protected function getDefaultPreFilters()
{
return [
new ActionFilter\HttpMethod([ActionFilter\HttpMethod::METHOD_POST]),
new ActionFilter\Csrf(),
new ActionFilter\Authentication(),
];
}
}
| Фильтр | Что проверяет |
|---|---|
HttpMethod | Разрешённый метод запроса |
Csrf | Токен сессии — защита от подделки запроса |
Authentication | Пользователь авторизован |
Scope | Откуда допустим вызов: AJAX, REST |
ContentType | Тип содержимого запроса |
Фильтры для отдельных действий
Если одно действие должно быть доступно без авторизации, а остальные — нет, описывается конфигурация действий:
<?php
public function configureActions()
{
return [
'getItem' => [
'prefilters' => [
new ActionFilter\HttpMethod([ActionFilter\HttpMethod::METHOD_GET]),
],
],
];
}
Указанный здесь набор заменяет фильтры по умолчанию для этого действия.
Пустой массив 'prefilters' => [] отключает все проверки —
применяйте это осознанно.
Ошибки
Ошибки возвращаются не исключением, а через накопитель:
<?php
use Bitrix\Main\Error;
public function addToCartAction(int $productId, int $quantity): ?array
{
if ($quantity <= 0) {
$this->addError(new Error('Количество должно быть больше нуля', 'BAD_QUANTITY'));
return null;
}
if (!$this->checkProductExists($productId)) {
$this->addError(new Error('Товар не найден', 'NOT_FOUND'));
return null;
}
return ['status' => 'added'];
}
Второй аргумент — код ошибки. Он удобен на клиенте: по нему можно различать ситуации, не разбирая текст сообщения.
Формат ответа
Контроллер всегда отдаёт одинаковую структуру. При успехе:
{
"status": "success",
"data": { "status": "added" },
"errors": []
}
При ошибке:
{
"status": "error",
"data": null,
"errors": [
{ "message": "Товар не найден", "code": "NOT_FOUND" }
]
}
Предсказуемый формат — одно из главных преимуществ подхода: клиентский код пишется один раз и работает со всеми действиями.
Вызов с фронтенда
Через BX.ajax.runAction
BX.ajax.runAction('project:controller.catalog.getItem', {
data: { id: 42 }
}).then(function (response) {
console.log(response.data);
}, function (response) {
response.errors.forEach(function (error) {
console.error(error.code, error.message);
});
});
Имя действия собирается из пространства имён, пути к классу и имени метода без суффикса.
Через обычный fetch
Если подключать библиотеку ядра не хочется, действие вызывается напрямую:
const formData = new FormData();
formData.append('id', '42');
formData.append('sessid', BX.bitrix_sessid());
fetch('/bitrix/services/main/ajax.php?action=project:controller.catalog.getItem', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(result => console.log(result));
Токен сессии здесь передаётся вручную — иначе фильтр Csrf отклонит запрос.
Контроллер внутри компонента
Если действия относятся к конкретному компоненту, контроллеры описываются
в файле ajax.php рядом с class.php, а вызов адресуется
через имя компонента. Так логика остаётся рядом с тем, к чему относится.
Устройство компонентов разобрано в статье
Создание компонента в Битрикс.
Отладка
Что проверять, если действие не вызывается:
-
Имя действия. Пространство имён в нижнем регистре, суффикс
Actionне указывается. - Автозагрузка класса. Если класс не зарегистрирован, ядро его не найдёт.
-
Метод запроса. При фильтре
HttpMethodс POST запрос GET будет отклонён. -
Токен сессии. Самая частая причина отказа при вызове
через
fetch. -
Ответ во вкладке «Сеть». В
errorsобычно написано, что именно не так.
Частые ошибки
-
Суффикс
Actionуказан в вызове. Действие не находится. - Все фильтры отключены «чтобы заработало». Обработчик становится доступен кому угодно с любого сайта.
-
Исключения вместо
addError(). Клиент получает не JSON, а страницу ошибки. -
Вывод внутри действия. Любой
echoломает разбор ответа. -
Нет проверки прав в действии. Фильтр
Authenticationпроверяет только факт авторизации, но не право на конкретную операцию.
Итог
Контроллеры D7 закрывают всё, что в самописных AJAX-обработчиках приходится делать вручную: проверку токена, ограничение метода запроса, разбор и приведение параметров, единый формат ответа с ошибками.
Минимальный рабочий набор — класс-наследник Controller, метод
с суффиксом Action, регистрация в автозагрузке и фильтры
Csrf с HttpMethod. Отключать фильтры ради того,
чтобы запрос прошёл, не стоит: именно они и есть основная ценность этого механизма.
