Как подключить бота к Системе взаимодействия 1С без потери внешнего вебхука

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой IT и автоматизация бизнеса
← На главную

При интеграции внешних ботов (например, ботов мессенджера MAX или Telegram) с Системой взаимодействия 1С через раздел Настройки сообщений из других приложений разработчики часто сталкиваются с проблемой: платформа 1С автоматически переопределяет адрес вебхука бота на свой шлюз (сервис 1С:Диалоги), из-за чего сторонний обработчик перестает получать события. Разберем, почему покупка локального Сервера взаимодействия не исправит данную ситуацию, и рассмотрим практические способы решения задачи.

Выясним причину: почему перетирается вебхук бота

Проанализируем базовый принцип работы Bot API большинства современных мессенджеров. На один токен бота платформы позволяют зарегистрировать только один активный URL для приема вебхуков. При подключении интеграции встроенные механизмы 1С отправляют запрос к API мессенджера и перезаписывают URL вебхука на собственный адрес.

Развертывание локального экземпляра 1С:Сервера взаимодействия (1С:Диалоги) не решает проблему, так как логика работы модуля интеграции остается прежней: сервер регистрирует свой внутренний URL для получения входящих сообщений. Тратить бюджет компании на покупку локального сервера взаимодействия исключительно ради сохранения вебхука не имеет смысла.

Варианты архитектурных решений

Рассмотрим основные подходы, которые позволяют сохранить текущую автоматизацию бота и одновременно использовать функционал 1С:

  1. Использование сервиса-прокладки (Webhook Proxy / Relay): настроим вебхук бота на единый промежуточный шлюз (легковесный HTTP-сервис). Получая событие от платформы мессенджера, прокси дублирует JSON-пакет сразу в два направления — в существующий вебхук вашей логики и в шлюз Системы взаимодействия 1С.
  2. Разделение ботов по назначению: создадим двух независимых ботов. Первый используется исключительно операторами через штатные 1С:Диалоги для диалогов с клиентами, а второй обслуживает фоновые процессы, триггерные рассылки и системные команды.
  3. Программное управление Системой взаимодействия через 1С: откажемся от автоматической привязки через 1С:Диалоги. Входящие запросы принимаем на опубликованный в 1С HTTP-сервис, после чего программно создаем обсуждения с помощью объекта СистемаВзаимодействия (метод СоздатьОбсуждение()) и записываем входящие сообщения методом ЗаписатьСообщение(). Для обратной связи перехватываем отправку сообщений операторами в 1С и отправляем запросы в API бота.

Пример программной отправки файлов и сообщений в API бота

Разберем по шагам реализацию отправки отчетов и файлов в мессенджер средствами встроенного языка 1С без использования сторонних внешних компонент. Процесс состоит из трех этапов: получение ссылки для загрузки, передача файла через multipart/form-data и отправка итогового сообщения с вложением.

Посмотрим на пример экспортной процедуры:


Процедура ОтправитьФайлВMax(ПутьКФайлу, IDЧата, ТокенБота, ИмяФайлаОтчета = "ФайлОтчета.xlsx", ТекстСообщения = "Отправляю файл") Экспорт

    // 1. Формируем заголовки авторизации
    ЗаголовкиАвторизации = Новый Соответствие;
    ЗаголовкиАвторизации.Вставить("Authorization", ТокенБота);

    // 2. Получаем временный URL для загрузки файла
    HTTPСоединение = Новый HTTPСоединение("platform-api.max.ru", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
    HTTPЗапрос = Новый HTTPЗапрос("/uploads?type=file", ЗаголовкиАвторизации);
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

    Если HTTPОтвет.КодСостояния <> 200 Тогда
        ВызватьИсключение "Ошибка при получении URL для загрузки: " + HTTPОтвет.КодСостояния + " - " + HTTPОтвет.ПолучитьТелоКакСтроку();
    КонецЕсли;

    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку());
    ОтветМетаЗагрузки = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();

    URLДляЗагрузки = ОтветМетаЗагрузки.url;

    // 3. Разбираем полученный URL для отправки бинарных данных
    РазборURL = СтрРазделить(URLДляЗагрузки, "/", Ложь);
    СерверЗагрузки = РазборURL[1];
    ПутьЗагрузки   = СтрЗаменить("/" + СтрСоединить(РазборURL, "/"), "/https:/" + СерверЗагрузки, "");

    // Формируем тело Multipart/form-data
    Boundary = "----WebKitFormBoundary" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);

    ПотокВПамяти = Новый ПотокВПамяти;
    ЗаписьДанных = Новый ЗаписьДанных(ПотокВПамяти);

    ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
    ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""data""; filename=""" + ИмяФайлаОтчета + """");
    ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/octet-stream");
    ЗаписьДанных.ЗаписатьСтроку("");
    ЗаписьДанных.Записать(ДвоичныеДанныеФайла);
    ЗаписьДанных.ЗаписатьСтроку("");
    ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--");
    ЗаписьДанных.Закрыть();

    ТелоЗапросаЗагрузки = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();

    HTTPСоединениеЗагрузки = Новый HTTPСоединение(СерверЗагрузки, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
    HTTPЗапросЗагрузки = Новый HTTPЗапрос(ПутьЗагрузки);
    HTTPЗапросЗагрузки.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
    HTTPЗапросЗагрузки.УстановитьТелоИзДвоичныхДанных(ТелоЗапросаЗагрузки);

    HTTPОтветЗагрузки = HTTPСоединениеЗагрузки.ОтправитьДляОбработки(HTTPЗапросЗагрузки);

    Если HTTPОтветЗагрузки.КодСостояния <> 200 Тогда
        ВызватьИсключение "Ошибка при загрузке файла: " + HTTPОтветЗагрузки.КодСостояния;
    КонецЕсли;

    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(HTTPОтветЗагрузки.ПолучитьТелоКакСтроку());
    ДанныеФайла = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();

    // 4. Отправляем сообщение с прикрепленным файлом
    HTTPЗапросСообщения = Новый HTTPЗапрос("/messages?user_id=" + IDЧата, ЗаголовкиАвторизации);
    HTTPЗапросСообщения.Заголовки.Вставить("Content-Type", "application/json");

    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписьJSON.ЗаписатьНачалоОбъекта();
    ЗаписьJSON.ЗаписатьИмяСвойства("text");
    ЗаписьJSON.ЗаписатьЗначение(ТекстСообщения);

    ЗаписьJSON.ЗаписатьИмяСвойства("attachments");
    ЗаписьJSON.ЗаписатьНачалоМассива();
    ЗаписьJSON.ЗаписатьНачалоОбъекта();
    ЗаписьJSON.ЗаписатьИмяСвойства("type");
    ЗаписьJSON.ЗаписатьЗначение("file");
    ЗаписьJSON.ЗаписатьИмяСвойства("payload");
    ЗаписатьJSON(ЗаписьJSON, ДанныеФайла);
    ЗаписьJSON.ЗаписатьКонецОбъекта();
    ЗаписьJSON.ЗаписатьКонецМассива();
    ЗаписьJSON.ЗаписатьКонецОбъекта();

    СтрокаТелаЗапроса = ЗаписьJSON.Закрыть();
    HTTPЗапросСообщения.УстановитьТелоИзСтроки(СтрокаТелаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

    HTTPОтветСообщения = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапросСообщения);

    Если HTTPОтветСообщения.КодСостояния <> 200 Тогда
        ВызватьИсключение "Ошибка отправки сообщения: " + HTTPОтветСообщения.ПолучитьТелоКакСтроку();
    КонецЕсли;

КонецПроцедуры

Рекомендации по оптимизации кода

Рассмотрим важные нюансы при работе с Bot API через HTTP-запросы в 1С:

  1. Отправка в группы и каналы: чтобы отправить сообщение не конкретному пользователю, а в групповой чат, замените в строке запроса параметр user_id на chat_id.
  2. Отказ от блокирующих циклов: если платформа мессенджера обрабатывает файл асинхронно и возвращает ошибку неготовности вложения (attachment.not.ready), избегайте пустых циклов ожидания по текущей дате, так как они создают предельную нагрузку на процессор. Надежнее вынести отправку в ФоновыеЗадания или проверять статус готовности вложения повторными запросами.
← На главную