Перейти к содержанию

Pull-команда передает изменение с сервера на открытую страницу. С ее помощью браузер может обновить статус задачи, счетчик или карточку объекта без перезагрузки. PHP отправляет команду через CPullStack::AddByUser, а JavaScript принимает ее через BX.PULL.subscribe и меняет интерфейс.

Проверьте отправку и получение команды на примере двух страниц. В одной вкладке пользователь нажимает кнопку, в другой появляется текст «Отчет 42 готов.». Так можно проверить доставку команды и работу обработчика без перезагрузки страницы.

Как команда обновляет страницу

Команда проходит от PHP через сервер очередей к обработчику в браузере:

  1. PHP-код выбирает получателя и передает модулю pull имя команды и данные.

  2. Сервер очередей доставляет команду подключенному браузеру пользователя.

  3. JavaScript-обработчик принимает данные и меняет нужный элемент страницы.

Доставленная команда не меняет страницу автоматически. Нужное действие выполняет JavaScript-обработчик. Получателем является пользователь, а не отдельная вкладка. Подробнее о пути команды читайте в статье Введение и принципы работы.

Подготовить окружение

Сначала настройте модуль и сервер очередей по статье Настройка модуля и сервера очередей. Если окружение уже готово, переходите к созданию файлов. У администратора установки уточните адрес сервера для подключения браузера и используемый транспорт. Эти сведения понадобятся при диагностике.

Пример выполняется в публичной части сайта. Войдите под тестовым пользователем и откройте две вкладки в одной сессии. Для проверки доставки другому пользователю понадобится вторая учетная запись и отдельный профиль браузера.

Если композитный кеш включен, добавьте /local/pull-demo/* в поле Маска исключения в настройках композитного сайта. Если композитный кеш выключен, этот шаг не нужен. При дополнительном кешировании HTML на прокси исключите каталог и из него. Назначение исключения описано в статье Композитный сайт.

Создайте каталог /local/pull-demo/ на тестовой установке. В нем будут два файла: index.php для получения команды и send.php для отправки. Пути ниже указаны относительно корня сайта.

PHP и JavaScript используют одинаковые имена: модуль example.reports, команду reportReady и параметр reportId. Сохраните их в обеих частях примера. Отчет 42 здесь условный. Код сообщает о готовности, но не формирует файл и не сохраняет данные.

Подключить получение команд

Объявите использование Push and Pull в публичной части сайта, затем создайте страницу с обработчиком команды.

Объявить использование модуля в публичной части

Обработчик OnGetDependentModule сообщает модулю pull, что код example.reports использует Push and Pull в публичной части. Вызов Loader::includeModule() подключает PHP API модуля, но не заменяет обработчик зависимости.

Добавьте обработчик в /local/php_interface/init.php. Сохраните существующий код файла. Если файла нет, создайте его с открывающим тегом <?php.

// Объявляем использование Push and Pull в публичной части
AddEventHandler('pull', 'OnGetDependentModule', static function () {
    return [
        'MODULE_ID' => 'example.reports',
        'USE' => ['PUBLIC_SECTION'],
    ];
});

Значение MODULE_ID связывает зависимость с кодом example.reports. Параметр USE с PUBLIC_SECTION задает работу в публичной части. Отдельный модуль отчетов для примера не нужен. В собственном модуле такую зависимость регистрируют при установке.

Создать страницу получателя

Создайте /local/pull-demo/index.php. Страница проверяет авторизацию, подключает PHP-модуль и клиентскую библиотеку pull.client, затем регистрирует обработчик команды:

<?php

use Bitrix\Main\Loader;
use Bitrix\Main\UI\Extension;

require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/header.php';

$APPLICATION->SetTitle('Получение команды Push and Pull');

// Проверяем авторизацию до работы с персональными командами
if (!$USER->IsAuthorized())
{
    echo '<p>Войдите на сайт и откройте страницу повторно.</p>';
}
elseif (!Loader::includeModule('pull'))
{
    echo '<p>Не удалось подключить модуль pull.</p>';
}
else
{
    // Подключаем клиент для получения команд в браузере
    Extension::load('pull.client');
    ?>
    <p>Получатель: <?= (int)$USER->GetID() ?></p>
    <p id="pull-demo-client">Подготовка обработчика...</p>
    <p id="pull-demo-report" aria-live="polite">Отчет 42: ожидание команды.</p>
    <p id="pull-demo-count">Получено команд: 0</p>
    <p>
        <a href="/local/pull-demo/send.php" target="_blank" rel="noopener">
            Открыть форму отправки
        </a>
    </p>

    <script>
    BX.ready(function () {
        const clientNode = document.getElementById('pull-demo-client');
        const reportNode = document.getElementById('pull-demo-report');
        const countNode = document.getElementById('pull-demo-count');
        let receivedCount = 0;

        if (!BX.PULL || typeof BX.PULL.subscribe !== 'function')
        {
            clientNode.textContent = 'Клиент Push and Pull недоступен.';
            return;
        }

        // Регистрируем обработчик команды о готовности отчета
        BX.PULL.subscribe({
            moduleId: 'example.reports',
            command: 'reportReady',
            callback: function (params) {
                // Принимаем только данные отчета, который показан на странице
                if (!params || params.reportId !== 42 || typeof params.text !== 'string')
                {
                    return;
                }

                // Обновляем текст без HTML-разметки и считаем полученные команды
                reportNode.textContent = params.text;
                receivedCount += 1;
                countNode.textContent = 'Получено команд: ' + receivedCount;
            }
        });

        clientNode.textContent = 'Обработчик reportReady зарегистрирован.';
    });
    </script>
    <?php
}

// Завершаем страницу штатно, чтобы выполнился эпилог
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/footer.php';

После загрузки появится надпись «Обработчик reportReady зарегистрирован». Она подтверждает регистрацию функции, но еще не доставку команды. Для проверки создайте страницу отправителя.

Получатель должен быть открыт до отправки. Дождитесь загрузки страницы, затем отправьте команду. Если текст не изменился, оставьте страницу открытой и перейдите к разделу Найти причину сбоя доставки команды.

Отправить команду из PHP

Создайте /local/pull-demo/send.php. Страница показывает форму и при ее отправке вызывает CPullStack::AddByUser для текущего авторизованного пользователя:

<?php

use Bitrix\Main\Loader;

require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/header.php';

$APPLICATION->SetTitle('Отправка команды Push and Pull');

// Проверяем авторизацию до работы с персональными командами
if (!$USER->IsAuthorized())
{
    echo '<p>Войдите на сайт и откройте страницу повторно.</p>';
}
elseif (!Loader::includeModule('pull'))
{
    echo '<p>Не удалось подключить модуль pull.</p>';
}
else
{
    // Отправляем команду пользователю текущей сессии
    $recipientId = (int)$USER->GetID();

    // GET только показывает форму, POST запускает отправку
    if ($_SERVER['REQUEST_METHOD'] === 'POST')
    {
        // Проверяем токен перед вызовом API
        if (!check_bitrix_sessid())
        {
            echo '<p>Проверка сессии не пройдена. Обновите страницу и повторите отправку.</p>';
        }
        else
        {
            // Передаем команду и данные для обработчика reportReady
            \CPullStack::AddByUser($recipientId, [
                'module_id' => 'example.reports',
                'command' => 'reportReady',
                'params' => [
                    'reportId' => 42,
                    'text' => 'Отчет 42 готов.',
                ],
            ]);

            echo '<p>Вызов отправки выполнен. Проверьте страницу получателя.</p>';
        }
    }
    ?>
    <p>Получатель: <?= $recipientId ?></p>
    <form method="post" action="/local/pull-demo/send.php">
        <?= bitrix_sessid_post() ?>
        <button type="submit">Сообщить о готовности отчета 42</button>
    </form>
    <?php
}

// Завершаем страницу штатно, чтобы выполнился эпилог
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/footer.php';

GET-запрос открывает форму, POST-запрос отправляет команду текущему пользователю. Перед отправкой код проверяет CSRF-токен: bitrix_sessid_post() добавляет его в форму, а check_bitrix_sessid() проверяет связь запроса с текущей сессией.

Получатель и данные заданы на сервере, изменить их через форму нельзя. В приложении перед отправкой дополнительно проверьте право пользователя на конкретный отчет. Авторизация не заменяет эту проверку.

Поля отправителя должны соответствовать подписке в браузере:

|

|| Поле PHP | Значение | Использование в JavaScript || || module_id | example.reports | Совпадает с moduleId подписки || || command | reportReady | Совпадает с command подписки || || params.reportId | Целое число 42 | Позволяет проверить, к какому отчету относится команда || || params.text | Строка Отчет 42 готов. | Заменяет текст в элементе страницы || |#

Сообщение «Вызов отправки выполнен» не подтверждает доставку. Результат проверяйте на странице получателя: текст должен измениться, счетчик — увеличиться.

Модуль отправляет накопленную команду при штатном завершении приложения. Отправитель должен подключить /bitrix/footer.php и пройти эпилог — завершающий этап обработки страницы. Вызов die или exit сразу после добавления команды может прервать этот путь.

Совет

Для AJAX, агента и CLI выберите способ завершения в статье Отправка команд из PHP.

Получить команду и обновить интерфейс

Метод BX.PULL.subscribe регистрирует обработчик команды с указанными moduleId и command. Функция callback получает параметры команды напрямую: params.reportId и params.text.

Обработчик проверяет номер отчета и тип текста, затем меняет содержимое элемента через textContent. HTML-теги в полученной строке отобразятся как текст, а не создадут элементы страницы.

Повторная команда снова установит текст «Отчет 42 готов.» и увеличит счетчик. Он считает вызовы обработчика после открытия страницы, а не выполненные операции. По счетчику нельзя сделать вывод о доставке ровно один раз.

HTTP-ответ формы не меняет вкладку получателя. Ее обновляет только обработчик pull-команды. Для отправки конкретному пользователю подписка по тегу через CPullWatch не нужна.

Проверить результат

Сначала подтвердите доставку текущему пользователю, затем проверьте изоляцию двух учетных записей. При сбое определите, на каком этапе остановился обмен.

Получить контрольную команду

  1. Авторизуйтесь на тестовом сайте и откройте /local/pull-demo/index.php. Дождитесь завершения загрузки страницы и надписи «Обработчик reportReady зарегистрирован».

  2. Откройте форму отправки по ссылке. Сверьте идентификатор получателя на обеих вкладках. Он должен совпадать.

  3. Нажмите «Сообщить о готовности отчета 42». Дождитесь завершения запроса на странице отправителя.

  4. Вернитесь на первую вкладку без ее перезагрузки и проверьте текст и счетчик.

  5. Повторно нажмите кнопку на странице отправителя.

Ожидаемый результат: текст изменился на «Отчет 42 готов.», счетчик увеличился. После повторной отправки текст остался прежним, а счетчик снова увеличился.

Для наблюдения отведите, например, 30 секунд. Это интервал проверки, а не гарантированное время доставки. Если результата нет, перейдите к разделу Найти причину сбоя доставки команды. Успешная повторная отправка не подтверждает доставку первой команды.

Проверить изоляцию пользователей

  1. Оставьте получателя первого пользователя открытым. В отдельном профиле браузера войдите под вторым пользователем и откройте обе тестовые страницы. Убедитесь, что идентификаторы двух пользователей различаются.

  2. Отправьте команду из формы второго пользователя. Убедитесь, что текст изменился, а счетчик увеличился. Так вы проверите, что второй клиент получает команды.

  3. Запишите значения обоих счетчиков. Отправьте команду из формы первого пользователя: его счетчик должен увеличиться, счетчик второго — остаться прежним.

  4. Повторите проверку в обратную сторону. Увеличиться должен только счетчик второго пользователя. Наблюдайте обе страницы в течение того же контрольного интервала.

Ожидаемый результат: при отправке меняется только счетчик выбранного пользователя. Две вкладки одной учетной записи для этой проверки не подходят.

Найти причину сбоя доставки команды

На странице получателя откройте инструменты разработчика Chrome через F12. Проверьте ошибки JavaScript во вкладке Console. Затем откройте Network и перезагрузите страницу.

Найдите запрос клиента во вкладке Network и отправьте новую команду. Способ проверки WebSocket и других вариантов подключения описан в статье Диагностика и обслуживание Push and Pull.

Во вкладке Sources поставьте точку останова на первой строке callback и повторите отправку. Если выполнение остановилось, проверьте params: ожидаются число 42 в reportId и строка в text. Если обработчик не вызван, проверьте получение сообщения и совпадение имен модуля и команды.

|

|| Симптом | Что проверить | Ожидаемый результат || || На странице появляется сообщение о необходимости входа | Авторизацию в текущем профиле браузера | Обе вкладки работают от одного пользователя || || Модуль или клиент недоступен | Установку pull, зависимость в init.php, загрузку pull.client и ошибки JavaScript | На странице появляется надпись о регистрации обработчика || || Форма сообщает об ошибке сессии | Свежесть страницы и наличие CSRF-токена в POST-запросе | После обновления формы проверка проходит || || Вызов отправки выполнен, но команды нет | Завершение POST-запроса в Network отправителя, совпадение идентификаторов, запросы и ошибки соединения в Network получателя | Запрос отправителя завершен, получатель подключен к настроенному серверу || || Команда есть, но текст не меняется | Совпадение module_id, command, типа и значения reportId, наличие строки text | Обработчик проходит проверку параметров || |#

Если запрос отправителя завершился и получатель выбран правильно, но команды нет, проверьте отправку из PHP. Для разбора с администратором сохраните время отправки, идентификатор получателя и текст ошибки. В общедоступный отчет не включайте секреты каналов и сессионные токены.

Перенести пример в приложение

Перед подключением данных приложения проверьте обработку параметров:

  1. Измените params.text в отправителе и отправьте команду. На странице должен появиться новый текст.

  2. Замените reportId на 43 и повторите отправку. Обработчик отчета 42 должен пропустить команду без изменения счетчика.

  3. Верните reportId со значением 42.

Перед отправкой уведомления сохраните результат операции и проверьте права получателя. При открытии страницы и восстановлении связи читайте сохраненное состояние. Одна команда не заменяет хранилище результатов.

Учебная страница создает подписку один раз за загрузку. В интерфейсе, который пользователь многократно открывает и закрывает, сохраняйте функцию отписки, возвращаемую BX.PULL.subscribe, и вызывайте ее при закрытии.

Если результат нужен только запросу, который его вычисляет, достаточно HTTP-ответа. Pull-команда нужна, когда изменение должна получить другая открытая страница.

В статье Отправка команд из PHP выберите способ отправки нескольким получателям. Затем по статье Обработка команд в JavaScript добавьте чтение состояния и проверьте снятие обработчиков.

При сбое начните с проверок этой статьи и продолжите по статье Настройка модуля и сервера очередей. Другие причины сбоев разбирает статья Диагностика и обслуживание Push and Pull.

По завершении проверки удалите тестовые страницы и добавленный обработчик зависимости, если они больше не нужны.