ГлавнаяБлогAJAX в 1С-Битрикс: актуальные способы вместо CPHttpRequest

AJAX в 1С-Битрикс: актуальные способы вместо CPHttpRequest

Рамиль Юналиев
Рамиль Юналиев
E-Commerce Lead
10 июля 2026 г.
5 мин чтения

В 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.

Для загрузки файла тем же способом вместо URLSearchParamsFormData, 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 в админке Битрикс.