При интеграции 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--
Важные моменты:
Content-Type указывается параметр boundary.-- + boundary.-- + boundary + --.CRLF (Символы.ВК + Символы.ПС).Поскольку встроенные средства 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, Символы.ПС, "").
Выясним причину, по которой сервер может не видеть границу. Часто это происходит из-за неверно указанного заголовка 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.НеИспользовать);
Проанализируем процесс отправки. Для работы с защищенными соединениями (HTTPS) необходимо использовать объект ЗащищенноеСоединениеOpenSSL.
Соединение = Новый HTTPСоединение("stage.ismet.kz", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
Попытка
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
КодСостояния = Ответ.КодСостояния;
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();
Если КодСостояния = 200 Тогда
Сообщить("Запрос успешно обработан: " + ТекстОтвета);
Иначе
Сообщить("Ошибка сервера (" + КодСостояния + "): " + ТекстОтвета);
КонецЕсли;
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;
Рассмотрим подробнее ситуации, которые приводят к неудаче даже при наличии кода:
no multipart boundary found: Скорее всего, вы установили тело запроса с использованием BOM или забыли добавить два дефиса -- перед границей внутри самого тела. Проверьте также, что в заголовке Content-Type после слова boundary= нет лишних кавычек, если их не требует спецификация конкретного API.Required request part 'content' is not present: Сервер не смог найти блок данных с указанным именем. Проверьте заголовок Content-Disposition. Там должно быть строго name="content". Лишние пробелы или точки с запятой в конце строки (как в сообщении 23 форума) могут привести к некорректному распознаванию атрибута.АдресРесурса. Эти данные передаются в конструктор HTTPСоединение. В HTTPЗапрос передается только путь (Path).UTF-8 и явно отключайте ИспользованиеByteOrderMark. Многие современные Java-серверы (Spring/Tomcat) крайне чувствительны к лишним байтам в начале потока данных.Если вы используете платформу 1С версии 8.3.15 и выше, рекомендуем обратить внимание на новые возможности работы с бинарными данными. Вместо сборки тела в строке можно использовать ЗаписьДанных и ПотокВПамяти. Это позволяет избежать проблем с кодировками и дает возможность передавать файлы "как есть", не кодируя их предварительно в Base64 (если это поддерживает API), что значительно экономит оперативную память при передаче больших объемов данных.
Подводя итог, можно сказать, что успех отправки multipart/form-data из 1С зависит от ювелирной точности формирования текстового блока. Любой лишний пробел или некорректный символ переноса строки приведет к тому, что сервер не сможет "разобрать" пакет на составляющие. Для комплексного освоения различных методов передачи данных и работы с заголовками подойдёт интерактивный обучающий курс по HTTP-запросам в 1С.