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

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

При интеграции 1С с внешними сервисами, такими как системы маркировки (например, ИС МПТ в Казахстане или «Честный знак» в РФ), разработчики часто сталкиваются с необходимостью отправки данных в формате multipart/form-data. Этот тип запроса используется, когда нужно передать одновременно несколько разнородных блоков данных, например, XML-файл документа и отсоединенную электронную подпись к нему.

Типичная проблема заключается в том, что сервер возвращает ошибку 500 с диагностикой Required request part 'content' is not present или no multipart boundary was found, хотя в Postman аналогичный запрос отрабатывает корректно. В данной статье мы разберем по шагам, как правильно сформировать такой запрос в 1С, избежав распространенных ошибок. Для интерактивной отладки и проверки веб-запросов прямо внутри платформы можно использовать инструмент для тестирования REST API в 1С.

Постановка задачи и анализ структуры запроса

Для начала проанализируем, как должен выглядеть корректный HTTP-запрос. Формат multipart/form-data подразумевает наличие уникального разделителя (boundary), который отделяет части тела запроса друг от друга. Рассмотрим пример структуры:


POST /api/v3/true-api/edo-api/outgoing-documents/formal HTTP/1.1
Host: server.com
Content-Type: multipart/form-data; boundary=----MyBoundary123
Authorization: Bearer [токен]

----MyBoundary123
Content-Disposition: form-data; name="content"

[Данные в формате Base64]
----MyBoundary123
Content-Disposition: form-data; name="signature"

[Данные подписи в формате Base64]
----MyBoundary123--

Важные моменты:

  1. В заголовке Content-Type указывается параметр boundary.
  2. Каждая часть начинается с -- + boundary.
  3. Тело завершается строкой -- + boundary + --.
  4. Между заголовками части и ее содержимым должна быть пустая строка (двойной перенос).
  5. В качестве переноса строк протокол HTTP требует использовать связку CRLF (Символы.ВК + Символы.ПС).

Шаг 1. Формирование тела запроса вручную

Поскольку встроенные средства 1С (до версии 8.3.15) не имели автоматического конструктора для мультипарт-запросов, самым надежным способом остается ручная сборка тела в текстовой переменной. Мы воспользуемся объектом ТекстовыйДокумент для управления строками.

Рассмотрим пример кода для формирования тела:


// Генерируем уникальную границу
Разделитель = "----" + СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");

ТелоЗапроса = Новый ТекстовыйДокумент();
// Устанавливаем корректный разделитель строк для HTTP (CRLF)
ТелоЗапроса.РазделительСтрок = Символы.ВК + Символы.ПС;

// Часть 1: Контент (XML в Base64)
ТелоЗапроса.ДобавитьСтроку("--" + Разделитель);
ТелоЗапроса.ДобавитьСтроку("Content-Disposition: form-data; name=""content""");
ТелоЗапроса.ДобавитьСтроку(""); // Пустая строка перед данными
ТелоЗапроса.ДобавитьСтроку(ДанныеBase64);

// Часть 2: Подпись (Signature в Base64)
ТелоЗапроса.ДобавитьСтроку("--" + Разделитель);
ТелоЗапроса.ДобавитьСтроку("Content-Disposition: form-data; name=""signature""");
ТелоЗапроas.ДобавитьСтроку(""); // Пустая строка перед данными
ТелоЗапроса.ДобавитьСтроку(ПодписьBase64);

// Финальная граница
ТелоЗапроса.ДобавитьСтроку("--" + Разделитель + "--");

СтрокаТела = ТелоЗапроса.ПолучитьТекст();

Обратите внимание: при получении Base64 через функцию Base64Строка(), 1С часто вставляет невидимые переносы строк. Их необходимо удалить перед вставкой в тело запроса с помощью СтрЗаменить(СтрокаBase64, Символы.ПС, "").

Шаг 2. Настройка HTTP-запроса и заголовков

Выясним причину, по которой сервер может не видеть границу. Часто это происходит из-за неверно указанного заголовка Content-Type или лишних данных в АдресРесурса. Разберем правильную настройку объекта HTTPЗапрос.


АдресРесурса = "/api/v3/true-api/edo-api/outgoing-documents/formal";
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);

// Указываем тип контента ОБЯЗАТЕЛЬНО с тем же boundary, что и в теле
HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);

// Устанавливаем тело из сформированной строки
// Важно: отключаем Byte Order Mark (BOM), иначе сервер выдаст ошибку парсинга
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаТела, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

Шаг 3. Отправка и обработка результата

Проанализируем процесс отправки. Для работы с защищенными соединениями (HTTPS) необходимо использовать объект ЗащищенноеСоединениеOpenSSL.


Соединение = Новый HTTPСоединение("stage.ismet.kz", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());

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

Типичные ошибки и их решения

Рассмотрим подробнее ситуации, которые приводят к неудаче даже при наличии кода:

  1. Ошибка no multipart boundary found: Скорее всего, вы установили тело запроса с использованием BOM или забыли добавить два дефиса -- перед границей внутри самого тела. Проверьте также, что в заголовке Content-Type после слова boundary= нет лишних кавычек, если их не требует спецификация конкретного API.
  2. Ошибка Required request part 'content' is not present: Сервер не смог найти блок данных с указанным именем. Проверьте заголовок Content-Disposition. Там должно быть строго name="content". Лишние пробелы или точки с запятой в конце строки (как в сообщении 23 форума) могут привести к некорректному распознаванию атрибута.
  3. Неверный формат адреса: Не указывайте протокол (http/https) и хост в АдресРесурса. Эти данные передаются в конструктор HTTPСоединение. В HTTPЗапрос передается только путь (Path).
  4. Проблемы с кодировкой: Всегда используйте UTF-8 и явно отключайте ИспользованиеByteOrderMark. Многие современные Java-серверы (Spring/Tomcat) крайне чувствительны к лишним байтам в начале потока данных.

Рекомендация для новых версий платформы

Если вы используете платформу 1С версии 8.3.15 и выше, рекомендуем обратить внимание на новые возможности работы с бинарными данными. Вместо сборки тела в строке можно использовать ЗаписьДанных и ПотокВПамяти. Это позволяет избежать проблем с кодировками и дает возможность передавать файлы "как есть", не кодируя их предварительно в Base64 (если это поддерживает API), что значительно экономит оперативную память при передаче больших объемов данных.

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

← На главную