Как отправить изображение в Telegram из 1С с помощью HTTP-запроса?

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

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

Постановка задачи и выбор метода API

Для отправки фотографий в Telegram Bot API используется метод sendPhoto. Согласно документации, этот метод принимает несколько параметров, наиболее важными из которых являются chat_id (идентификатор чата) и photo (сам файл изображения). Если мы хотим отправить файл непосредственно из памяти или с диска сервера 1С, нам необходимо использовать POST-запрос с типом контента multipart/form-data. Это стандарт передачи двоичных данных, где тело запроса разделяется на части с помощью уникального разделителя — boundary.

Шаг 1: Подготовка данных и формирование границ запроса

Прежде чем собирать запрос, нам необходимо подготовить уникальную строку-разделитель. Она должна быть уникальной, чтобы сервер Telegram мог однозначно определить, где заканчивается один параметр и начинается другой. Рассмотрим пример формирования Boundary:

Boundary = "----"+Строка(Новый УникальныйИдентификатор());

Далее мы подготовим основные параметры: токен бота, адрес сервера и идентификатор чата. Обратите внимание, что идентификатор чата должен быть приведен к строковому виду без лишних разделителей групп разрядов. Для этого удобно использовать функцию Формат.

Шаг 2: Сборка multipart-тела через временные файлы

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

  1. Создаем начальный текстовый фрагмент, содержащий Boundary и описание параметров (например, chat_id).
  2. Добавляем описание секции photo с указанием имени файла и типа контента.
  3. Записываем само изображение во временный файл.
  4. Создаем финальный текстовый фрагмент, закрывающий Boundary.
  5. Объединяем все фрагменты в один файл отправки.

Проанализируем пример кода, реализующий эту логику:


// Формируем начальный фрагмент
ИмяФайлаОтправкиНачало = ПолучитьИмяВременногоФайла("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");
ОбъединитьФайлы(МассивФайлов, ИмяФайлаТела);

Шаг 3: Важность разделителей строк (CRLF)

Одной из самых коварных ошибок при ручном формировании HTTP-запросов является использование только символа перевода строки Символы.ПС (LF). Стандарт HTTP требует использования пары CRLF — Символы.ВК + Символы.ПС. Многие современные веб-серверы, включая Telegram, могут вернуть ошибку 400 Bad Request, если увидят некорректные разделители. Как мы выяснили, именно добавление Символы.ВК часто решает проблему "невидимости" фото в запросе.

Шаг 4: Выбор правильного метода отправки

Выясним причину, по которой стандартный метод Получить() объекта 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 Тогда
        Сообщить("Картинка успешно отправлена!");
    Иначе
        Сообщить("Ошибка: " + Ответ.ПолучитьТелоКакСтроку());
    КонецЕсли;
Исключение
    Сообщить("Ошибка соединения: " + ОписаниеОшибки());
КонецПопытки;

Шаг 5: Оптимизация через использование потоков (Streams)

Начиная с версии платформы 8.3.15, мы можем отказаться от медленных операций с диском (временных файлов) и использовать потоки в памяти. Это работает значительно быстрее и избавляет от проблем с блокировкой файлов или правами доступа. Вместо ОбъединитьФайлы мы последовательно записываем данные в ПотокВПамяти.

Проанализируем этот современный подход:

  1. Создаем ПотокВПамяти.
  2. Используем ЗаписьДанных для записи текстовых частей и двоичных данных картинки.
  3. Устанавливаем тело запроса из потока методом УстановитьТелоИзПотока().

Это исключает создание трех-четырех временных файлов на диске для каждого сообщения.

Дополнительные рекомендации по работе с Telegram API

Разберем несколько важных нюансов, которые помогут сделать вашу интеграцию более надежной:

Таким образом, мы проанализировали процесс отправки изображений от формирования структуры multipart-запроса до отправки на сервер. Основными залогами успеха являются: использование метода POST (через ОтправитьДляОбработки), корректное указание Boundary в заголовках, соблюдение стандарта CRLF для переноса строк и правильная сборка бинарного тела запроса.

← На главную