Push & Pull для гостей в Битриксе: настройка веб-сокетов для неавторизованных пользователей

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

Код из примеров есть здесь - https://github.com/solopovsergey/dzen/tree/main/push_and_pull_for_guest

Про это же в официальной документации - https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=43&CHAPTER_ID=05413&LESSON_PATH=3913.3516.4776.5413

Установка и настройка модулей

В первую очередь проверяем чтобы были установлены модули

  1. Push and Pull (pull)
  2. Веб-аналитика (statistic)
  3. REST API (rest)
push_neavtorizovan1.png

Для примера будем использовать Push server облачный от 1С-Битрикс, доступный только для активной лицензии.
push_neavtorizovan2.png

Определение идентификатора гостя

Далее добавляем обработчик события, в котором будем указывать идентификатор гостя для модуля Push and Pull. Модуль веб аналитики обеспечит нас этим идентификатором. Добавляем php код в файл /bitrix/php_interface/init.php

$eventManager = \Bitrix\Main\EventManager::getInstance();

//для автоподключения
$eventManager->addEventHandler(
    "pull",
    "OnGetDependentModule",
    ["CSolopovSergePushAndPullForGuest", 'pullOnGetDependentModule']
);

// для установки идентификатора для гостя
$eventManager->addEventHandler(
    "main",
    "OnProlog",
    ["CSolopovSergePushAndPullForGuest", 'mainOnProlog'],
    2
);

class CSolopovSergePushAndPullForGuest
{
    const MODULE_ID = 'bxmaker.authuserphone';

    public static function pullOnGetDependentModule()
    {
        return [
            'MODULE_ID' => self::MODULE_ID,
            'USE' => ["PUBLIC_SECTION"],
        ];
    }


    public static function mainOnProlog()
    {
        global $USER;
        //сразу подключим библиотеку для клиентской стороны,
        // можно перенести в header.php шаблона сайта
        \Bitrix\Main\UI\Extension::load('pull.client');

        // проверим чтобы еще не был определен
        if (defined('PULL_USER_ID')) {
            return;
        }

        // проверим чтобы польвзаотель был не атворизован
        if ($USER->IsAuthorized()) {
            return;
        }

        // обычная загрузка страницы, берем идентфикиатор от модуля веб аналитики (он уникальный)
        if (isset($_SESSION['SESS_GUEST_ID'])) {
            define('PULL_USER_ID', -1 * abs($_SESSION['SESS_GUEST_ID']));
            return;
        }

        // загрузка парамтеров конфигурации для push&pull в котором отклчюен учет статистики
        // используется при загрузке конфигурации, перемменная $_SESSION['SESS_GUEST_ID'] в запросе таком отсутствует
        $req = \Bitrix\Main\Application::getInstance()->getContext()->getRequest();
        if ((int)$req->getCookie('GUEST_ID')) {
            define('PULL_USER_ID', -1 * (int)$req->getCookie('GUEST_ID'));
        }
    }


    /**
     * Вернет идентфикиатор получателя уведомления для текущего пользователя
     * в зависимости от авторизованности пользователя
     * @return int|null
     */
    public static function getPullUserId()
    {
        if (defined('PULL_USER_ID')) {
            return constant('PULL_USER_ID');
        }

        if (is_object($GLOBALS['USER'])) {
            return (int)$GLOBALS['USER']->GetID();
        }

        return null;
    }

    /**
     * Отправка получателю команду с парамтерами
     * @param string $command
     * @param array $arParams
     * @param int $recipientId - получен от метода getPullUserId()
     * @return bool
     * @throws \Bitrix\Main\LoaderException
     */
    public static function sendCommand($recipientId, $command, $arParams = [])
    {
        if (!\Bitrix\Main\Loader::includeModule('pull')) {
            return false;
        }
        if (!\CPullOptions::GetNginxStatus()) {
            return false;
        }

        $arMessage = [
            'module_id' => self::MODULE_ID,
            'command' => $command,
            'params' => $arParams,
        ];

        $result = \Bitrix\Pull\Event::add($recipientId, $arMessage);
        if (!$result) {
            //..
        }
        return true;
    }
}

Проверка работы на клиенте

Чтобы проверить работу на клиенте, нужно в консоли браузера выполнить команду
BX.PULL.getDebugInfo();
Вывод должен быть примерно таким
push_neavtorizovan3.png

Ошибка - Config is not loaded

Если в выводе вы видите ошибку - Config error: config is not loaded

push_neavtorizovan4.png
необходимо в файл /urlrewrite.php добавить следующий код

array(
    'CONDITION' => '#^/rest/#',
    'RULE' => '',
    'ID' => NULL,
    'PATH' => '/bitrix/services/rest/index.php',
    'SORT' => 10,
),
push_neavtorizovan5.png

Сохраняем сделанные изменения, после этого нужно перезагрузить страницу и проверить заново - все должно работать.

Если не помогло, то нужно переключить в настройках модуля push and pull на использование локального сервера, сохранить и затем обратно вернуть на использование облачного варианта.

Получение сообщений в браузере

Для получения сообщения в браузере, добавляем следующий js код на страницу

BX.PULL.subscribe({
  moduleId: 'main', // нужно заменить на свое значение,
  command: 'hello',
  callback: function (params, extra, command) {
    alert('Получено сообщение по websocket, подробности в консоли браузера');
    console.warn('Receive message:', params.message.text)
  }.bind(this)
});

Отправка сообщений с сервера

Теперь для отправки сообщений по вебсокету в браузер пользователя (клиенту) можно воспользоваться методом


\CSolopovSergePushAndPullForGuest::sendCommand(
    \CSolopovSergePushAndPullForGuest::getPullUserId(),
    'hello',
    ['time' => time(), 'text' => 'world']
);

или без обертки


if (\Bitrix\Main\Loader::includeModule('pull') && \CPullOptions::GetNginxStatus()) {
    $userId = 0;
    if (defined('PULL_USER_ID')) {
        $userId = constant('PULL_USER_ID');
    } elseif (is_object($GLOBALS['USER'])) {
        $userId = (int)$GLOBALS['USER']->GetID();
    }

    $arMessage = [
        'module_id' => 'main',
        'command' => 'hello',
        'params' => [
            'time' => time(),
            'text' => 'world'
        ],
    ];

    $result = \Bitrix\Pull\Event::add($userId, $arMessage);
    if (!$result) {
//.. error
    }
}
 
Обратно к списку