Как реализовать API запрос с типом multipart/form-data в 1С при использовании метода PUT?

Программист 1С v8.3 (Управляемые формы) Промышленность, строительство и АПК
← На главную

При интеграции 1С с современными веб-сервисами, такими как «Базис-Облако» или другими промышленными API, разработчики часто сталкиваются с необходимостью передачи данных в формате multipart/form-data. Особую сложность вызывают запросы типа PUT, где требуется не только передать файл или параметр, но и строго соблюсти структуру разделителей (boundaries) и кодировку. В этой статье мы подробно разберем, как правильно сформировать такой запрос, избежать ошибок авторизации и корректно передать параметры серверу.

Разберем типичные ошибки при работе с multipart/form-data

Проанализируем ситуацию: автору необходимо изменить статус документа в стороннем сервисе. На первый взгляд, задача кажется тривиальной, но при реализации в 1С возникают следующие проблемы:

  1. Неверный HTTP-метод: Использование метода ОтправитьДляОбработки() в 1С по умолчанию инициирует POST-запрос. Если API ожидает PUT, сервер вернет ошибку 405 Method Not Allowed.
  2. Неправильная структура тела: Формат multipart/form-data требует жесткого соблюдения синтаксиса разделителей, включая дефисы и пустые строки.
  3. Проблема BOM (Byte Order Mark): При записи текстовых данных в поток 1С может добавить невидимый символ BOM, который сервер воспримет как ошибку в данных, что приведет к коду 400 Bad Request.
  4. Отсутствие Boundary в заголовках: Если в заголовке Content-Type не указан параметр boundary, сервер не сможет разделить переданные данные на отдельные поля формы.

Шаг 1: Формирование заголовков запроса

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

Проанализируем код формирования заголовков:


ВремГраница = СтрЗаменить(Новый УникальныйИдентификатор, "-", "");

Заголовки = Новый Соответствие;
Заголовки.Вставить("apiKey", "Ваш_Ключ_API");
Заголовки.Вставить("accept", "application/json");
// Обязательно указываем boundary прямо в типе контента
Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + ВремГраница);

Шаг 2: Подготовка тела запроса в формате multipart

Теперь рассмотрим, как правильно упаковать данные. Каждое поле в multipart/form-data начинается с разделителя, предваряемого двумя дефисами (--), за которыми следуют служебные заголовки поля и само значение. Выясним причину, по которой обычная склейка строк может не сработать: сервер ожидает строго определенные символы перевода строк — CRLF (Возврат каретки + Перевод строки).

Воспользуемся объектом ТекстовыйДокумент для удобной сборки тела:


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

// Начало блока параметра statusId
ТелоЗапроса.ДобавитьСтроку("--" + ВремГраница);
ТелоЗапроса.ДобавитьСтроку("Content-Disposition: form-data; name=""statusId""");
// Обязательная пустая строка перед значением
ТелоЗапроса.ДобавитьСтроку("");
ТелоЗапроса.ДобавитьСтроку("9"); // Значение статуса

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

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

Шаг 3: Отправка данных и борьба с BOM

Ключевым моментом является передача строки в тело HTTP-запроса без лишних символов. Рассмотрим метод УстановитьТелоИзСтроки. Здесь крайне важно установить третий параметр в значение ИспользованиеByteOrderMark.НеИспользовать. Если этого не сделать, 1С добавит в начало потока символы, указывающие на порядок байтов, что для веб-сервера будет выглядеть как «мусор» перед первой границей разделителя.

Также важно использовать правильный метод объекта HTTPСоединение. Для выполнения PUT-запроса в 1С используется метод Записать() или ВызватьHTTPМетод().

Посмотрим на финальную реализацию отправки:


// Создаем запрос
HTTPЗапрос = Новый HTTPЗапрос("api-cutting-public/orders/" + IDДокумента + "/status", Заголовки);

// Устанавливаем тело без BOM
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапросаСтрока, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

// Настраиваем защищенное соединение
Соединение = Новый HTTPСоединение("cloud.bazissoft.ru", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());

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

Почему это работает?

Давайте проанализируем, почему этот подход решает проблему. Во-первых, мы явно указали boundary в заголовках, что позволило парсеру сервера найти начало данных. Во-вторых, использование Символы.ВК + Символы.ПС обеспечило совместимость с требованиями протокола HTTP. В-третьих, отказ от JSON в пользу прямой передачи значения statusId в теле формы (как и ожидает формат multipart/form-data) устранил ошибку 400.

Важный совет: Если ваше API требует передачи нескольких полей, каждое из них должно быть отделено строкой --boundary, а завершаться вся конструкция должна строкой --boundary--. Никогда не забывайте про пустую строку после заголовка Content-Disposition внутри тела — это стандарт, без которого данные не будут прочитаны корректно.

Таким образом, комбинируя правильное управление потоками данных, контроль кодировок и корректные HTTP-методы, можно успешно интегрировать 1С с любыми современными облачными сервисами.

← На главную