Как отправить картинку POST-запросом (multipart/form-data) в 1С?

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

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

Проанализируем типичную ошибку при отправке файлов

Часто программисты пытаются передать параметры и сам файл, упаковывая их в структуру и преобразуя в JSON, при этом указывая заголовок, предназначенный для отправки файлов. Посмотрим на пример такого ошибочного кода:


Сайт = "media.sms-online.com";
Parameters = Новый Структура;
Parameters.Вставить("login", Логин);
Parameters.Вставить("image", Картинка); // Ошибка: сюда пытаются поместить двоичные данные или путь
Parameters.Вставить("sign", ХешСигн);

HTTPСоединение = Новый HTTPСоединение(Сайт,,,,,,Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос  = Новый HTTPЗапрос("/upload/");
Запись      = Новый ЗаписьJSON;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);  
Запись.УстановитьСтроку(ПараметрыJSON);
ЗаписатьJSON(Запись, Parameters);
СтрокаJSON = Запись.Закрыть();

HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data");
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
ОтветHTTP = HTTPСоединение.Post(HTTPЗапрос);

В результате сервер возвращает ошибку: Mandatory parameters missing: image (Обязательный параметр отсутствует: image). Выясним причину такого поведения.

Главная ошибка заключается в противоречии форматов. В 1С формируется тело запроса в формате JSON с помощью метода ЗаписатьJSON, но при этом в заголовке Content-Type указывается значение multipart/form-data. Сервер, читая заголовок, ожидает получить структуру, разделенную специальными границами (boundary), а вместо этого получает обычную текстовую строку JSON. Естественно, он не может найти в ней файл и выдает ошибку. Передача двоичных данных или Base64-строки внутрь JSON здесь не поможет, так как принимающая сторона ожидает классическую HTML-форму отправки файла.

Что делает функция curl_file_create в PHP?

Чтобы понять, как реализовать отправку в 1С, проанализируем, как это работает в PHP. Объект CURLFile сообщает библиотеке cURL, что запрос должен быть отправлен именно как форма (multipart). Под капотом система делает огромную работу: автоматически генерирует уникальный разделитель (Boundary), формирует бинарное тело запроса, прописывает метаданные файла (имя, MIME-тип) и подставляет сырые двоичные данные. В платформе 1С:Предприятие нет встроенной "одной кнопки" для создания такой структуры, поэтому весь пакет данных нам придется собрать вручную.

Пошаговая инструкция: как правильно собрать multipart/form-data в 1С

Рассмотрим алгоритм ручной сборки тела запроса. Нам потребуется использовать объекты ПотокВПамяти и ЗаписьДанных, чтобы корректно склеить текстовые параметры и бинарные данные картинки.

  1. Создание разделителя (Boundary). Разделитель — это уникальная строка, которая не должна случайно встретиться внутри самих передаваемых данных. Обычно мы генерируем ее на основе уникального идентификатора.
  2. Подготовка текстовых параметров. Каждый параметр (например, login или sign) должен начинаться с разделителя, содержать заголовок с именем параметра, пустую строку и само значение.
  3. Добавление файла. Блок файла также начинается с разделителя, содержит имя параметра, имя самого файла и его MIME-тип (например, image/jpeg). Далее записываются двоичные данные картинки.
  4. Завершение тела запроса. В конце обязательно ставится финальный разделитель с двумя дефисами в начале и в конце.

Пример реализации отправки файла на встроенном языке 1С

Разберем готовый шаблон кода, который решает поставленную задачу. Этот код склеивает данные в правильном бинарном формате.


// 1. Генерируем уникальный разделитель (Boundary)
УИД = Строка(Новый УникальныйИдентификатор());
Boundary = "----1CBoundary" + СтрЗаменить(УИД, "-", "");

// 2. Инициализируем поток для сборки тела запроса
ПотокТела = Новый ПотокВПамяти;
ЗаписьДанных = Новый ЗаписьДанных(ПотокТела, КодировкаТекста.UTF8);

// Символы переноса строки, требуемые стандартом
ПереносСтроки = Символы.ВК + Символы.ПС;

// 3. Функция/Процедура добавления текстового параметра (псевдокод для понимания структуры)
// Добавляем параметр "login"
ТекстПараметра = "--" + Boundary + ПереносСтроки +
    "Content-Disposition: form-data; name=""login""" + ПереносСтроки +
    ПереносСтроки +
    ЛогинПользователя + ПереносСтроки;
ЗаписьДанных.Записать(ТекстПараметра);

// Добавляем параметр "sign"
ТекстПараметра = "--" + Boundary + ПереносСтроки +
    "Content-Disposition: form-data; name=""sign""" + ПереносСтроки +
    ПереносСтроки +
    ХешСигн + ПереносСтроки;
ЗаписьДанных.Записать(ТекстПараметра);

// 4. Добавляем файл (картинку)
ТекстЗаголовкаФайла = "--" + Boundary + ПереносСтроки +
    "Content-Disposition: form-data; name=""image""; filename=""photo.jpg""" + ПереносСтроки +
    "Content-Type: image/jpeg" + ПереносСтроки +
    ПереносСтроки;
ЗаписьДанных.Записать(ТекстЗаголовкаФайла);

// Записываем сами двоичные данные файла
ДДКартинки = Новый ДвоичныеДанные(ПутьККартинке);
ЗаписьДанных.Записать(ДДКартинки);
ЗаписьДанных.Записать(ПереносСтроки); // Перенос после файла

// 5. Завершаем тело запроса финальным разделителем
ФинальныйРазделитель = "--" + Boundary + "--" + ПереносСтроки;
ЗаписьДанных.Записать(ФинальныйРазделитель);

ЗаписьДанных.Закрыть();

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

// 6. Формируем HTTP-запрос и отправляем
HTTPСоединение = Новый HTTPСоединение("media.sms-online.com",,,,,, Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = Новый HTTPЗапрос("/upload/");

// ВАЖНО: Указываем сгенерированный Boundary в заголовке
HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);

HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТела);

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

Проанализируем этот код. Мы отказались от использования JSON и собираем запрос по правилам стандарта RFC для HTML-форм. Использование объектов ПотокВПамяти и ЗаписьДанных позволяет легко комбинировать строковые данные (заголовки, имена параметров) и чистые бинарные данные картинки, не искажая их кодировкой. Обратите особое внимание на расстановку переносов строк (комбинация Символы.ВК + Символы.ПС) — серверы очень чувствительны к их правильному расположению. Также критически важно передать сгенерированный Boundary в заголовок Content-Type запроса, иначе сервер не поймет, где начинаются и заканчиваются блоки данных.

← На главную