Интеграция 1С с мессенджером Telegram является одной из самых востребованных задач в современной автоматизации. Отправка текстовых сообщений обычно не вызывает затруднений, однако передача медиафайлов, таких как фотографии или отчеты в формате картинок, требует глубокого понимания протокола HTTP и особенностей формирования multipart/form-data запросов. В данной статье мы подробно разберем, как реализовать отправку изображения, проанализируем типичные ошибки и рассмотрим современные способы оптимизации этого процесса.
Для отправки фотографий в Telegram Bot API используется метод sendPhoto. Согласно документации, этот метод принимает несколько параметров, наиболее важными из которых являются chat_id (идентификатор чата) и photo (сам файл изображения). Если мы хотим отправить файл непосредственно из памяти или с диска сервера 1С, нам необходимо использовать POST-запрос с типом контента multipart/form-data. Это стандарт передачи двоичных данных, где тело запроса разделяется на части с помощью уникального разделителя — boundary.
Прежде чем собирать запрос, нам необходимо подготовить уникальную строку-разделитель. Она должна быть уникальной, чтобы сервер Telegram мог однозначно определить, где заканчивается один параметр и начинается другой. Рассмотрим пример формирования Boundary:
Boundary = "----"+Строка(Новый УникальныйИдентификатор());
Далее мы подготовим основные параметры: токен бота, адрес сервера и идентификатор чата. Обратите внимание, что идентификатор чата должен быть приведен к строковому виду без лишних разделителей групп разрядов. Для этого удобно использовать функцию Формат.
Традиционный подход в 1С заключается в использовании временных файлов и их последующем объединении. Это связано с тем, что текстовые данные (заголовки секций) и двоичные данные (само изображение) нужно соединить в один поток. Рассмотрим алгоритм действий:
Boundary и описание параметров (например, chat_id).photo с указанием имени файла и типа контента.Boundary.Проанализируем пример кода, реализующий эту логику:
// Формируем начальный фрагмент
ИмяФайлаОтправкиНачало = ПолучитьИмяВременногоФайла("txt");
ФайлОтправкиНачало = Новый ЗаписьТекста(ИмяФайлаОтправкиНачало, КодировкаТекста.UTF8);
ТекстДляОтправки = "--" + Boundary + Символы.ВК + Символы.ПС;
ТекстДляОтправки = ТекстДляОтправки + "Content-Disposition: form-data; name=""chat_id""" + Символы.ВК + Символы.ПС + Символы.ВК + Символы.ПС + СтрокаIDЧата + Символы.ВК + Символы.ПС;
ТекстДляОтправки = ТекстДляОтправки + "--" + Boundary + Символы.ВК + Символы.ПС;
ТекстДляОтправки = ТекстДляОтправки + "Content-Disposition: form-data; name=""photo""; filename=""image.jpg""" + Символы.ВК + Символы.ПС;
ТекстДляОтправки = ТекстДляОтправки + "Content-Type: image/jpeg" + Символы.ВК + Символы.ПС + Символы.ВК + Символы.ПС;
ФайлОтправкиНачало.Записать(ТекстДляОтправки);
ФайлОтправкиНачало.Закрыть();
// Формируем финальный фрагмент
ИмяФайлаОтправкиКонец = ПолучитьИмяВременногоФайла("txt");
ФайлаОтправкиКонец = Новый ЗаписьТекста(ИмяФайлаОтправкиКонец, КодировкаТекста.UTF8);
ФайлаОтправкиКонец.Записать(Символы.ВК + Символы.ПС + "--" + Boundary + "--");
ФайлаОтправкиКонец.Закрыть();
// Объединяем файлы
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ИмяФайлаОтправкиНачало);
МассивФайлов.Добавить(ИмяФайлаКартинки);
МассивФайлов.Добавить(ИмяФайлаОтправкиКонец);
ИмяФайлаТела = ПолучитьИмяВременногоФайла("txt");
ОбъединитьФайлы(МассивФайлов, ИмяФайлаТела);
Одной из самых коварных ошибок при ручном формировании HTTP-запросов является использование только символа перевода строки Символы.ПС (LF). Стандарт HTTP требует использования пары CRLF — Символы.ВК + Символы.ПС. Многие современные веб-серверы, включая Telegram, могут вернуть ошибку 400 Bad Request, если увидят некорректные разделители. Как мы выяснили, именно добавление Символы.ВК часто решает проблему "невидимости" фото в запросе.
Выясним причину, по которой стандартный метод Получить() объекта HTTPСоединение не подходит для нашей задачи. Метод Получить() инициирует GET-запрос. В протоколе HTTP GET-запросы не предполагают передачи тела (Body). Хотя 1С позволяет установить имя файла тела для HTTPЗапрос, при вызове Получить() платформа может просто проигнорировать эти данные.
Для отправки файлов необходимо использовать метод ОтправитьДляОбработки() (POST-запрос) или универсальный метод ВызватьHTTPМетод(). Рассмотрим правильный пример инициализации соединения и отправки:
HTTPЗапрос = Новый HTTPЗапрос("bot" + Токен + "/sendPhoto");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
HTTPЗапрос.УстановитьИмяФайлаТела(ИмяФайлаТела);
Соединение = Новый HTTPСоединение("api.telegram.org", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
Попытка
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
Сообщить("Картинка успешно отправлена!");
Иначе
Сообщить("Ошибка: " + Ответ.ПолучитьТелоКакСтроку());
КонецЕсли;
Исключение
Сообщить("Ошибка соединения: " + ОписаниеОшибки());
КонецПопытки;
Начиная с версии платформы 8.3.15, мы можем отказаться от медленных операций с диском (временных файлов) и использовать потоки в памяти. Это работает значительно быстрее и избавляет от проблем с блокировкой файлов или правами доступа. Вместо ОбъединитьФайлы мы последовательно записываем данные в ПотокВПамяти.
Проанализируем этот современный подход:
ПотокВПамяти.ЗаписьДанных для записи текстовых частей и двоичных данных картинки.УстановитьТелоИзПотока().Это исключает создание трех-четырех временных файлов на диске для каждого сообщения.
Разберем несколько важных нюансов, которые помогут сделать вашу интеграцию более надежной:
file_id. Используйте этот ID для последующих отправок — это мгновенно и экономит ваш трафик.Картинка в 1С для предварительного сжатия или изменения разрешения.filename старайтесь использовать латиницу. Если имя файла в 1С содержит русские буквы, это может привести к ошибке обработки multipart-запроса на стороне сервера.HTTPСоединение (параметр Таймаут), чтобы избежать зависания сеанса при плохом интернет-соединении.Таким образом, мы проанализировали процесс отправки изображений от формирования структуры multipart-запроса до отправки на сервер. Основными залогами успеха являются: использование метода POST (через ОтправитьДляОбработки), корректное указание Boundary в заголовках, соблюдение стандарта CRLF для переноса строк и правильная сборка бинарного тела запроса.