При интеграции 1С с Telegram ботом разработчики часто сталкиваются с задачей отправки файлов, таких как PDF-документы, в ответ на действия пользователя в боте. Это особенно актуально, когда данные о нажатии кнопки или запросе документа приходят в 1С через механизм вебхуков. В данном руководстве мы подробно рассмотрим, как реализовать отправку файлов методом sendDocument из 1С, учитывая особенности работы с вебхуками и форматированием HTTP-запросов.
Изначально может показаться логичным попытаться отправить файл в качестве прямого ответа на входящий вебхук от Telegram. Однако, как показал опыт многих разработчиков, включая участников данного обсуждения, такой подход не является рабочим. Телеграм ожидает быстрый ответ с подтверждением получения обновления (обычно HTTP 200), а не файл. Отправка файла – это отдельная операция, которую должен инициировать ваш HTTP-сервис 1С.
Прежде чем перейти к коду, давайте разберем ключевые концепции:
getUpdates: Это альтернативный механизм, при котором ваш 1С-сервис сам периодически обращается к серверам Telegram для получения новых событий. В этом случае 1С является инициатором связи.sendDocument: Это метод Telegram Bot API, предназначенный для отправки файлов. Он может принимать файл как:
file_id: Если файл уже был загружен в Telegram ранее.multipart/form-data. Максимальный размер файла для этого метода обычно составляет 50 МБ.Критически важно: Когда ваш HTTP-сервис 1С получает запрос от Telegram через вебхук, он должен его обработать, а затем отдельным HTTP-запросом обратиться к Telegram API методом sendDocument для отправки файла. Это позволяет не «зависать» вебхуку и корректно передать файл.
sendDocument в 1СРассмотрим подробный пример кода для 1С, который демонстрирует, как сформировать и отправить POST-запрос с файлом в формате multipart/form-data. Этот подход использует временные файлы для правильного объединения текстовых и двоичных частей запроса.
Прежде всего, нам понадобятся ваш токен бота, идентификатор чата, путь к файлу и уникальный разделитель для multipart/form-data.
МойToken = "ВАШ_ТОКЕН_БОТА"; // Замените на реальный токен вашего бота
АдресTelegramAPI = "api.telegram.org";
// Если нужен прокси:
// ПроксиАдрес = "159.138.22.170";
// ПроксиПорт = 3128;
ЧатID = "882646417"; // Идентификатор чата, куда отправляем файл
ПутьКФайлу = "C:\1.pdf"; // Полный путь к отправляемому PDF-файлу
// Создаем уникальный разделитель (Boundary) для multipart/form-data
// Это строка, которая гарантированно не встречается в содержимом файла
Boundary = "----"+Строка(Новый УникальныйИдентификатор);
РазделительСтрок = Символы.ВК + Символы.ПС; // CRLF
multipart/form-dataФормат multipart/form-data требует, чтобы тело запроса было разделено на части с помощью специальной строки-разделителя (Boundary). Каждая часть содержит заголовки (например, Content-Disposition, Content-Type) и само содержимое поля. Двоичные данные файла должны быть вставлены между соответствующими текстовыми частями.
В 1С для корректной работы с двоичными данными в multipart/form-data удобно использовать механизм объединения файлов. Мы создадим три временных файла:
chat_id, заголовки для document).Затем эти три файла будут объединены в один и отправлены.
Файл = Новый Файл(ПутьКФайлу);
Если Не Файл.Существует() Тогда
Сообщить("Ошибка: Файл по пути " + ПутьКФайлу + " не найден.");
Возврат;
КонецЕсли;
// 1. Формируем начальную часть запроса (chat_id и заголовки для document)
МассивФайловДляОбъединения = Новый Массив;
ИмяВременногоФайлаНачало = ПолучитьИмяВременногоФайла("txt");
МассивФайловДляОбъединения.Добавить(ИмяВременногоФайлаНачало);
ФайлОтправкиНачало = Новый ЗаписьТекста(ИмяВременногоФайлаНачало, КодировкаТекста.UTF8);
НачальныеДанные = "--" + Boundary + РазделительСтрок
+ "Content-Disposition: form-data; name=""chat_id""" + РазделительСтрок + РазделительСтрок
+ СтрЗаменить(Строка(ЧатID), Символы.НПП, "") + РазделительСтрок // Важно: chat_id приводим к строке
+ "--" + Boundary + РазделительСтрок
+ "Content-Disposition: form-data; name=""document""; filename=""" + Файл.Имя + """" + РазделительСтрок
+ "Content-Type: application/pdf" + РазделительСтрок + РазделительСтрок; // Два разделителя перед бинарными данными
ФайлОтправкиНачало.ЗаписатьСтроку(НачальныеДанные);
ФайлОтправкиНачало.Закрыть();
// 2. Добавляем сам PDF-файл в массив для объединения
МассивФайловДляОбъединения.Добавить(ПутьКФайлу);
// 3. Формируем конечную часть запроса
ИмяВременногоФайлаКонец = ПолучитьИмяВременногоФайла("txt");
МассивФайловДляОбъединения.Добавить(ИмяВременногоФайлаКонец);
ФайлаОтправкиКонец = Новый ЗаписьТекста(ИмяВременногоФайлаКонец, КодировкаТекста.UTF8);
КонечныеДанные = РазделительСтрок + "--" + Boundary + "--" + РазделительСтрок;
ФайлаОтправкиКонец.ЗаписатьСтроку(КонечныеДанные);
ФайлаОтправкиКонец.Закрыть();
// Объединяем все части в один итоговый файл
ИмяИтоговогоФайла = ПолучитьИмяВременногоФайла("tmp"); // Важно: использовать расширение, чтобы 1С не пыталась его парсить как текст
ОбъединитьФайлы(МассивФайловДляОбъединения, ИмяИтоговогоФайла);
Мы использовали СтрЗаменить(Строка(ЧатID), Символы.НПП, "") для chat_id. Это необходимо, чтобы гарантировать, что chat_id будет корректной строкой без непечатаемых символов, которые могут возникнуть при преобразовании числа в строку в некоторых версиях 1С.
Теперь, когда у нас есть готовый файл с телом запроса, мы можем отправить его в Telegram API.
// Настройка прокси, если необходимо
// Прокси = Новый ИнтернетПрокси;
// Прокси.Установить("https", ПроксиАдрес, ПроксиПорт);
// Прокси.Установить("http", ПроксиАдрес, ПроксиПорт);
// Устанавливаем соединение с Telegram API по HTTPS (порт 443)
// Если используете прокси, раскомментируйте Прокси
СоединениеHTTP = Новый HTTPСоединение(АдресTelegramAPI, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
// Формируем адрес запроса к методу sendDocument
АдресЗапроса = "bot" + МойToken + "/sendDocument";
ЗапросHTTP = Новый HTTPЗапрос(АдресЗапроса);
ЗапросHTTP.Метод = "POST"; // Всегда используем POST для отправки файлов
// Устанавливаем заголовки запроса
ЗапросHTTP.Заголовки.Вставить("Connection", "keep-alive");
ЗапросHTTP.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
// Указываем, что тело запроса находится в файле
ЗапросHTTP.УстановитьИмяФайлаТела(ИмяИтоговогоФайла);
// Отправляем запрос и обрабатываем ответ
Попытка
ОтветHTTP = СоединениеHTTP.Отправить(ЗапросHTTP);
Если ОтветHTTP.Код = 200 Тогда
Сообщить("Файл успешно отправлен в Telegram. Ответ: " + ОтветHTTP.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
Иначе
Сообщить("Ошибка при отправке файла. Код ответа: " + ОтветHTTP.Код);
Сообщить("Тело ответа: " + ОтветHTTP.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
КонецЕсли;
Исключение
Сообщить("Произошла ошибка при выполнении HTTP-запроса: " + ОписаниеОшибки());
КонецПопытки;
// Удаляем временные файлы
УдалитьФайлы(ИмяВременногоФайлаНачало);
УдалитьФайлы(ИмяВременногоФайлаКонец);
УдалитьФайлы(ИмяИтоговогоФайла);
После того, как мы научились отправлять файл, рассмотрим, как это встроить в логику обработки вебхуков. Ваш HTTP-сервис 1С получает запрос от Telegram. Внутри обработчика этого вебхука вы выполняете следующие шаги:
chat_id и команду пользователя.sendDocument.
// Пример обработчика HTTP-сервиса в 1С (псевдокод)
Функция ОбработатьHTTPЗапрос(Запрос) Экспорт
// 1. Получаем и парсим входящие данные от Telegram
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
ДанныеЗапроса = ПрочитатьJSON(СтрокаJSON); // Предполагаем наличие функции ПрочитатьJSON
Чат = ДанныеЗапроса.message.chat.id; // Пример получения chat_id
// 2. Проверяем условие и инициируем отправку файла
Если ДанныеЗапроса.message.text = "Получить документ" Тогда
// Здесь вызываем процедуру, которая содержит код по отправке файла,
// аналогичный приведенному выше.
// Передаем в нее ЧатID и ПутьКФайлу
// Например: ОтправитьPDFВTelegram(Чат, "d:\1111.pdf");
Сообщить("Получена команда 'Получить документ', инициируем отправку файла...");
// ВАЖНО: здесь вызов функции, которая отправляет файл отдельным POST-запросом
Попытка
ОтправитьФайлМетодомSendDocument(Чат, "d:\1111.pdf"); // Пример вызова вашей функции
Исключение
Сообщить("Ошибка при отправке файла: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
// 3. Возвращаем HTTP-ответ 200, чтобы Telegram знал, что запрос обработан
Ответ = Новый HTTPСервисОтвет(200);
// Можно вернуть пустой JSON или просто пустой ответ.
// Пример:
// Ответ.УстановитьТелоИзСтроки("{""ok"": true}");
// Ответ.Заголовки.Вставить("Content-Type", "application/json");
Возврат Ответ;
КонецФункции
// Пример вспомогательной процедуры, которая инкапсулирует логику отправки файла
Процедура ОтправитьФайлМетодомSendDocument(ЧатID, ПутьКФайлу)
// ... Весь код из разделов "1. Подготовка данных" и "3. Установка HTTP-соединения"
// должен быть здесь, используя переданные ЧатID и ПутьКФайлу
// Не забудьте определить МойToken, АдресTelegramAPI и другие параметры.
МойToken = "ВАШ_ТОКЕН_БОТА";
АдресTelegramAPI = "api.telegram.org";
РазделительСтрок = Символы.ВК + Символы.ПС;
// ... остальная часть кода для формирования и отправки запроса
// как показано выше.
// Удаление временных файлов также должно быть здесь.
КонецПроцедуры
multipart/form-data запроса. Это может быть неправильный Boundary, отсутствующие пустые строки между заголовками и содержимым части, неверный Content-Type для файла или ошибки в структуре заголовков.
РазделительСтрок (Символы.ВК + Символы.ПС) используется последовательно и правильно, особенно перед двоичными данными файла.chat_id:
chat_id может приходить в виде числа, и при преобразовании его в строку в 1С могут появиться непечатаемые символы (например, Символы.НПП). Telegram API ожидает чистую строковую репрезентацию.
chat_id, приводя его к строке и удаляя непечатаемые символы, как показано: СтрЗаменить(Строка(ЧатID), Символы.НПП, "").sendDocument обычно это 50 МБ для новых файлов.Отправка PDF-файлов из 1С в Telegram бот методом sendDocument через вебхуки — это вполне реализуемая задача. Ключевым моментом является понимание того, что файл отправляется не как прямой ответ на входящий вебхук, а как отдельный POST-запрос к Telegram API, инициируемый вашим HTTP-сервисом. Правильное формирование multipart/form-data запроса с использованием механизма объединения временных файлов в 1С обеспечивает надежную передачу двоичных данных. Всегда помните о необходимости быстрого ответа на вебхук и корректной обработке chat_id. Следуя этим рекомендациям, вы сможете успешно интегрировать 1С с Telegram ботом для обмена документами.