Собственный Push&Pull клиент
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
Собственный клиент держит соединение с серверами Push&Pull напрямую: приложение меняет свое состояние и обновляет интерфейс сразу, не опрашивая REST.
Обмен устроен так. Серверная часть приложения публикует событие методом pull.application.event.add, событие попадает в канал приложения на серверах Push&Pull, а клиент читает канал по открытому соединению. Клиент подключается сразу к обоим каналам приложения. Определения терминов раздела и сроки жизни канала и конфигурации собраны в статье Интерактивность в приложениях: обзор методов.
Собственный клиент нужен, когда приложение работает отдельно от интерфейса Битрикс24: серверный процесс интеграции, десктопное приложение, веб-приложение на своем домене вне фрейма. Например, обработка на вашем сервере разбирает выгрузку несколько минут и по завершении сообщает об этом клиенту, а тот сразу показывает результат, не опрашивая сервер.
В других случаях подойдут решения из соседних статей:
- приложение открыто в Битрикс24, и достаточно штатного клиента — Push&Pull в браузере
- события нужны, когда страница приложения закрыта, а Битрикс24 открыт в браузере — PAGE_BACKGROUND_WORKER
- уведомить нужно пользователя вне интерфейса Битрикс24 — pull.application.push.add
Клиент работает только в контексте приложения. Конфигурацию подключения он запрашивает методом pull.application.config.get, которому нужен OAuth-токен и scope pull, а вебхук такой контекст не создает.
Что нужно перед началом
- установленное приложение со scope
pull - серверная часть, которая умеет вызывать REST с OAuth-токеном приложения
Конфигурацию подключения запрашивает серверная часть приложения — OAuth-токен остается на ней. Клиенту передайте только адрес сервера и параметры подключения из ответа.
CHANNEL_ID, jwt и clientId — это доступ к каналу. Тот, кто их получил, читает события приложения до конца срока жизни канала. Не выводите их в логи, не записывайте в открытые хранилища и не передавайте третьим сторонам.
Как подключиться к серверу
Сервер поддерживает два способа подключения: websocket и long polling. По умолчанию подключайтесь по websocket. Long polling нужен только для устройств без поддержки websocket или когда соединение регулярно срывается.
- Получите параметры подключения методом pull.application.config.get
- Проверьте
server.server_enabled. Значениеfalseозначает, что Push&Pull в этом Битрикс24 не настроен: подключаться не к чему, и переподключение не поможет - Возьмите из объекта
serverзащищенный адрес нужного типа —websocket_secureилиlong_pooling_secure. Параметры подключения передаются в строке запроса, поэтому незащищенныеwebsocketиlong_pollingберите только там, где защищенного адреса нет. Еслиserver.websocket_enabledравенfalse, websocket выключен — подключайтесь по long polling - Выберите, чем авторизовать подключение. Поля
jwtиclientIdвместе не приходят, поэтому веток всего две:- в ответе есть поле
jwt— передайте его в GET-параметреtoken. Каналы уже зашиты в токен,CHANNEL_IDне нужен. Токен выдает только сервер версии 5 и выше, поэтому в облачном Битрикс24 эта ветка не встречается - поля
jwtнет — соберите GET-параметрCHANNEL_IDиз значенийchannels.private.idиchannels.shared.id, именно в таком порядке и через/
- в ответе есть поле
- Если в ответе пришло поле
clientId, добавьте его к адресу отдельным параметром
Значение CHANNEL_ID можно подставить как есть или закодировать вместе со всей строкой запроса — сервер принимает оба варианта. При кодировании разделитель / превращается в %2F и остается разделителем.
Идентификаторы каналов не разбирайте на части: у личного канала значение id само содержит двоеточие, и это не разделитель каналов.
Публичные идентификаторы public_id и объект publicChannels для подключения не используются ни в одной из веток. Состав объекта server описан в разделе Объект server, поля канала — в разделе Объект канала shared и private, а условия, при которых приходят jwt и clientId, — в разделе Объект result.
Пример подключения по websocket к общему серверу Push&Pull:
wss://rtc-cloud-ms1.bitrix24.tech/subws/?CHANNEL_ID=beb502091dfc9b93d7fd648aa4ec332e%3A7cc478c89de71ec78bf4820d3d814a3e.4f5466742ca1e59e263fee732a7dbe002889ba91%2F1ab4f7a440cea35a1abccd5c2566c688.b33914ef342e5cd21e4fbcf4ac92acd2e9ea3755&clientId=fcda45d0859442735f07b8bb5825ded1&format=json
Пример подключения по websocket к собственному серверу Push&Pull. Адрес и путь задает администратор при настройке сервера, поэтому они отличаются от адресов общего сервера:
wss://rt.**put.your-domain-here**/sub/?CHANNEL_ID=46a437d2336d4a88e4e9b3cd956ecf45:6221e0eb48981fce67cf4756e82e8102.7910bb25e660bf211fdec15e33c5e25e4c3b644a/fb9f7e13dc3d595c5aefe1a0216c27a2.2887eebc6ae160713a732893462dce9d8e23a7b0
В первом примере адрес записан с процентным кодированием. Параметра format во втором примере нет: на собственном сервере версия по умолчанию — 2.
Пример подключения с токеном, когда в ответе метода пришло поле jwt:
wss://rt.**put.your-domain-here**/sub/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.**put_jwt_here**&format=json
В адресе подключения может быть до пяти GET-параметров:
CHANNEL_IDилиtoken— авторизация подключения, обязательно одно из двухclientId— только на общем сервере Push&Pullformat— формат командmidлибо параtagиtime— чтение истории канала
Параметры истории берут из последней полученной команды. Подключившись с ними, клиент один раз получит сообщения, которые пропустил, пока был отключен.
Запрашивайте конфигурацию заново, когда подходит к концу срок end одного из каналов или время exp самой конфигурации. В коробочной версии exp приходит не всегда — если поля нет, опирайтесь на end каналов и на команды config_expire и server_restart.
Как ведет себя открытое соединение
Чтобы читать события приложения, отправлять в сокет после подключения ничего не нужно: обмен односторонний, команды идут от сервера к клиенту.
Признак живого соединения — сообщения от сервера: кроме событий он регулярно шлет служебные. Штатный клиент Битрикс24 считает соединение зависшим, если не получил ни одного сообщения за 20 секунд, — закрывает сокет и переподключается. Держите в своем клиенте такое же правило по времени: долгую тишину считайте обрывом, а не затишьем.
Подключение по long polling
Long polling работает с теми же GET-параметрами, что и websocket, — меняется только базовый адрес, его берут из server по правилу шага 3. Имя поля long_pooling_secure приходит из API с опечаткой, pooling вместо polling; читайте его как есть.
Клиент держит один открытый GET-запрос и переоткрывает его после каждого ответа:
- Отправьте GET-запрос на собранный адрес
- Получили
200— разберите тело ответа как команды и сразу отправьте следующий запрос - Получили
304— команд не было, сразу отправьте следующий запрос - Получили любой другой статус — считайте это ошибкой подключения и выдержите задержку из раздела Работа с ошибками
- Ответа нет дольше 60 секунд — оборвите запрос сами и откройте новый
Штатный клиент Битрикс24 ждет ответа 60 секунд и не открывает следующий запрос, пока не завершился предыдущий. Держите то же правило — иначе в канал уйдет очередь параллельных запросов.
Общий формат команд от сервера
Читать события приложения можно в текстовом формате или в JSON — этого достаточно. Штатный клиент Битрикс24 умеет еще два режима, JSON-RPC и бинарный, но они нужны ему для служебного обмена, а не для чтения канала.
Формат зависит от версии сервера — она приходит в поле server.version ответа метода pull.application.config.get. На общем сервере Push&Pull версия всегда равна 4.
Для сервера версии 4 и выше добавьте при подключении GET-параметр &format=json — команды придут в формате JSON:
[
{"id":320146,"mid":"14526134350000000000320146","channel":"6221e0eb48981fce67cf4756e82e8102","tag":"672","time":"Thu, 29 Jun 2017 09:50:16 GMT","text":{},"extra":{}},
{"id":320147,"mid":"14526134350000000000320147","channel":"6221e0eb48981fce67cf4756e82e8102","tag":"673","time":"Thu, 29 Jun 2017 09:50:17 GMT","text":{},"extra":{}}
]
Для сервера версии 3 и ниже команды приходят текстом вида:
#!NGINXNMS!#{"id":320146,"mid":"14526134350000000000320146","channel":"6221e0eb48981fce67cf4756e82e8102","tag":"672","time":"Thu, 29 Jun 2017 09:50:16 GMT","text":{},"extra":{}}#!NGINXNME!#
#!NGINXNMS!#{"id":320147,"mid":"14526134350000000000320147","channel":"6221e0eb48981fce67cf4756e82e8102","tag":"673","time":"Thu, 29 Jun 2017 09:50:17 GMT","text":{},"extra":{}}#!NGINXNME!#
Чтобы разобрать такую команду, возьмите текст между маркерами #!NGINXNMS!# и #!NGINXNME!# и преобразуйте его в JSON.
В канал приходят все команды, включая управляющие команды модуля pull, поэтому фильтруйте их сами по полям text.module_id и text.command.
Сама команда в обоих форматах имеет единый вид:
{
"id": 320146,
"mid": "14526134350000000000320146",
"channel": "6221e0eb48981fce67cf4756e82e8102",
"tag": "672",
"time": "Mon, 03 Oct 2017 06:36:01 GMT",
"text": {
"module_id": "application",
"command": "test_event",
"params": {
"grid_id": 15,
"status": "done"
}
},
"extra": {
"server_time": "2017-10-03T08:36:01+02:00",
"server_time_unix": 1507012561,
"server_time_ago": 0,
"server_name": "rt1.bitrix24.com",
"revision_web": 19,
"revision_mobile": 3,
"channel": "6221e0eb48981fce67cf4756e82e8102"
}
}
где:
id— идентификатор сообщенияmid— идентификатор сообщения для восстановления истории, только для версии сервера 3 и вышеchannel— идентификатор канала, только для версии сервера 3 и выше. Для версии сервера 1 идентификатор приходит вextra.channel, а для версии 2 не приходит ни там, ни там — берите его из значения, которое сами подставили вCHANNEL_IDtag— E-tag для восстановления истории, для версии сервера 2 и нижеtime— время сообщения для восстановления истории, для версии сервера 2 и нижеtext— структура, описывающая действие команды:module_id— идентификатор модуля, отправившего команду. Для событий приложения это значение параметраMODULE_IDметода pull.application.event.add, по умолчаниюapplicationcommand— идентификатор командыparams— дополнительные данные для выполнения команды
extra— структура с дополнительными сведениями:server_time— время сервера на момент формирования команды в формате ATOMserver_time_unix— время сервера на момент формирования команды в формате Unix timestamp с долями секундыserver_time_ago— количество секунд, прошедших с момента отправки команды. Сервер это поле не присылает, его подставляет клиент, посчитав поserver_time_unixserver_name— имя сервера, отправившего командуrevision_web— ревизия протокола Push&Pull для браузерного клиентаrevision_mobile— ревизия протокола Push&Pull для мобильного клиентаchannel— идентификатор канала для версии сервера 1, смотрите описание поляchannelвыше
Как проверить подключение
Отправьте событие из серверной части методом pull.application.event.add с COMMAND, равным test_event. В канал должна прийти команда, у которой text.module_id равен application, а text.command — test_event.
Если команда не пришла, проверьте по порядку:
- соединение установлено и не закрылось сразу после открытия
CHANNEL_IDсобран по правилу из раздела Как подключиться к серверу и не потерял части при кодировании адреса- срок каналов не истек — сравните текущее время с
endиз ответа pull.application.config.get - событие отправлено с тем же
USER_ID, чей канал читает клиент, либо безUSER_ID— тогда оно уходит в общий канал
Работа с ошибками
Обрабатывать ошибки подключения обязательно: сервер заблокирует за подозрительную активность клиент, который переподключается без задержки. Конкретные интервалы ниже — ориентир, а не требование протокола.
Если подключение к серверу приводит к ошибкам, увеличивайте задержку перед следующей попыткой. Штатный клиент Битрикс24 выдерживает такие задержки:
- обрыв уже установленного соединения — 0,5 секунды
- после первой и второй неудачной попытки — 5 секунд
- после третьей и четвертой — 25 секунд
- с пятой по девятую — 45 секунд
- начиная с десятой — 60 секунд
Добавляйте к задержке случайную надбавку от 0 до 20%, чтобы клиенты не переподключались одновременно. Счетчик неудачных попыток сбрасывайте, как только соединение установилось.
Если websocket не поднимается несколько попыток подряд и соединение закрывается с кодом 1006 или 1008, на компьютере пользователя, скорее всего, заблокирован протокол websocket. В этом случае предусмотрите запасное подключение по long polling.
Полностью переходить на long polling стоит, только если по websocket не удалось подключиться ни разу. Если раньше соединение поднималось, переключайтесь временно и пробуйте websocket снова — штатный клиент возвращается к нему через 30 минут.
Управляющие команды сервера
Предусмотрите в клиенте обработку управляющих команд. Ниже показано содержимое поля text — сами команды приходят в том же конверте, что и события приложения.
channel_expire
Сервер сообщает, что срок работы канала истекает.
{
"module_id": "pull",
"command": "channel_expire",
"params": {
"action": "reconnect",
"channel": {
"id": "46a437d2336d4a88e4e9b3cd956ecf45.7910bb25e660bf211fdec15e33c5e25e4c3b644a",
"type": "shared"
},
"new_channel": {
"id": "fb9f7e13dc3d595c5aefe1a0216c27a2.2887eebc6ae160713a732893462dce9d8e23a7b0",
"start": "2017-06-28T09:57:48+02:00",
"end": "2017-06-28T21:57:48+02:00",
"type": "shared"
}
}
}
Параметры команды
|
Название |
Описание |
|
action |
Действие, которое должен выполнить клиент:
|
|
channel |
Информация о канале, для которого получена команда |
|
new_channel |
Информация о новом канале. Приходит, только если |
Как обработать команду
Когда придет команда channel_expire, выполните шаги в зависимости от значения action:
actionравенreconnect- замените информацию о текущем канале данными из
new_channel - переустановите подключение к серверу
- замените информацию о текущем канале данными из
actionравенget_config- отключитесь от сервера
- запросите новые данные о каналах методом pull.application.config.get
- установите подключение к серверу заново
config_expire и server_restart
Сервер сообщает, что его настройки изменились.
{
"module_id": "pull",
"command": "config_expire",
"params": {}
}
Команда server_restart приходит в том же виде, отличается только значение command:
{
"module_id": "pull",
"command": "server_restart",
"params": {}
}
Как обработать команды config_expire и server_restart
Если поступила команда config_expire или server_restart:
- отключитесь от сервера
- через случайный промежуток от 10 до 120 секунд запросите новые данные о каналах методом pull.application.config.get. Разброс нужен, чтобы после перезапуска сервера клиенты не пришли за конфигурацией одновременно
- установите подключение к серверу заново