Как отправить POST-запрос с типом multipart/form-data и передать файл из 1С в API Farpost

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

При интеграции 1С с современными веб-сервисами, такими как Farpost, программисты часто сталкиваются с необходимостью отправки данных в формате multipart/form-data. В отличие от простых GET-запросов или передачи JSON, этот формат требует строгого соблюдения структуры тела запроса, использования специальных разделителей (boundary) и правильной обработки двоичных данных. Разберем подробно, как реализовать такую выгрузку, основываясь на опыте решения реальной задачи.

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

Рассмотрим ситуацию: нам необходимо передать пакет данных на Endpoint: https://www.farpost.ru/good/packet/api/sync. Согласно документации API, запрос должен содержать следующие обязательные параметры:

  1. packetId — числовой идентификатор пакета.
  2. auth — строка авторизации (хеш-сумма).
  3. data — файл или бинарный контент (например, прайс-лист в формате XLS или XML).

Основная сложность заключается в том, что стандартные методы 1С не формируют структуру multipart/form-data автоматически "под капотом" так, как это делают браузеры. Нам придется собрать это тело вручную или использовать специальные приемы компоновки данных.

Подготовка защищенного соединения

Поскольку API работает по протоколу HTTPS, первым делом настроим защищенное соединение. Проанализируем код инициализации:


Прокси = Новый ИнтернетПрокси();
// Если требуется настройка прокси, указываем параметры здесь
Прокси.Установить("https",,);

SSL = Новый ЗащищенноеСоединениеOpenSSL(
    Новый СертификатКлиентаWindows(),
    Новый СертификатыУдостоверяющихЦентровWindows());

Попытка
    // Обратите внимание: имя сервера указывается без префикса https://
    HTTP = Новый HTTPСоединение("www.farpost.ru",,,,, 60, SSL);
Исключение
    Сообщить("Ошибка подключения: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

Здесь мы используем объект ЗащищенноеСоединениеOpenSSL для работы с TLS/SSL. Важно помнить, что в объекте HTTPСоединение первым параметром передается только адрес хоста (сервера), а путь к ресурсу будет указан позже в объекте запроса.

Что такое Boundary и зачем он нужен

Когда мы передаем данные в формате multipart/form-data, серверу нужно понимать, где заканчивается один параметр и начинается другой (особенно если один из них — это бинарный файл). Для этого используется Boundary — уникальная строка-разделитель. Выясним, как она выглядит в сыром HTTP-запросе:

Перед каждым параметром ставится разделитель с двумя дефисами в начале: --разделитель. После последнего параметра ставится финальный разделитель: --разделитель--. Если мы забудем про конечные дефисы, сервер будет вечно ждать продолжения данных и вернет ошибку 400 (Bad Request).

Пошаговое формирование тела запроса

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

Шаг 1. Генерируем уникальный разделитель. Лучше всего использовать УникальныйИдентификатор, чтобы исключить совпадение разделителя с контентом внутри файла.

Шаг 2. Записываем текстовые параметры. Каждый блок данных начинается с описания Content-Disposition.

Шаг 3. Внедряем файл. Для файла data мы должны указать не только имя параметра, но и filename, а также Content-Type самого файла.

Посмотрим на пример функции, которая собирает такой запрос:


Функция СформироватьТелоЗапроса(Знач PacketId, Знач Auth, Знач ПутьКФайлуПрайса, Boundary)
    ИмяФайлаТела = ПолучитьИмяВременногоФайла("txt");
    ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаТела, КодировкаТекста.UTF8);
    
    // 1. Параметр packetId
    ЗаписьТекста.ЗаписатьСтроку("--" + Boundary);
    ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""packetId""");
    ЗаписьТекста.ЗаписатьСтроку(""); // Пустая строка перед значением
    ЗаписьТекста.ЗаписатьСтроку(Строка(Format(PacketId, "ЧГ=0")));
    
    // 2. Параметр auth
    ЗаписьТекста.ЗаписатьСтроку("--" + Boundary);
    ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""auth""");
    ЗаписьТекста.ЗаписатьСтроку("");
    ЗаписьТекста.ЗаписатьСтроку(Auth);
    
    // 3. Параметр data (файл)
    ЗаписьТекста.ЗаписатьСтроку("--" + Boundary);
    ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""data""; filename=""price.xls""");
    ЗаписьТекста.ЗаписатьСтроку("Content-Type: application/vnd.ms-excel"); // Тип зависит от файла
    ЗаписьТекста.ЗаписатьСтроку("");
    ЗаписьТекста.Закрыть();
    
    // Теперь нужно дописать бинарные данные файла и закрывающий разделитель
    // Используем комбинирование файлов или потоков
    ФайлРезультат = Новый Файл(ИмяФайлаТела);
    // (Здесь логика дозаписи двоичных данных из файла прайса)
    
    Возврат ИмяФайлаТела;
КонецФункции

Важные нюансы работы с бинарными данными

Проанализируем распространенную ошибку: попытку закодировать файл в Base64. В контексте multipart/form-data для API Farpost это делать не нужно, если сервер ожидает именно бинарный поток. Если вы передадите Base64Строка(ДвоичныеДанные), сервер получит текстовый мусор вместо реального файла Excel и не сможет его прочитать.

Также обратим внимание на кодировку. Текстовые части (заголовки и строковые параметры) должны быть в кодировке UTF-8. Использование ANSI в 1С может привести к тому, что кириллица в именах файлов или значениях превратится в "кракозябры", и сервер вернет ERROR_REASON_EMPTY_REQUEST из-за нечитаемости параметров auth или data.

Окончательная отправка запроса

Когда тело запроса сформировано во временном файле, выполняем отправку. Не забудьте указать boundary в заголовке Content-Type, иначе сервер не поймет, как "нарезать" ваш запрос на части.


Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");
ПутьКТелу = СформироватьТелоЗапроса(11111, "секретный_хеш", "C:\price.xls", Boundary);

Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);

Запрос = Новый HTTPЗапрос("/good/packet/api/sync", Заголовки);
Запрос.УстановитьИмяФайлаТела(ПутьКТелу);

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

Резюме и рекомендации

Подведем итоги нашего исследования. Для успешной работы с POST-запросами и файлами в 1С следует придерживаться следующих правил:

  1. Используйте HTTPЗапрос и HTTPСоединение вместо устаревших методов. Это дает больше контроля над заголовками.
  2. Тщательно формируйте Boundary. Помните про два дефиса в начале каждой секции и два дефиса в конце финальной строки.
  3. Не кодируйте в Base64 без явного требования API. Большинство серверов ждут "чистый" бинарный контент файла после заголовков секции.
  4. Проверяйте кодировку. UTF-8 — стандарт де-факто для веб-интеграций.
  5. Следите за параметром auth. В Farpost это хеш, который часто зависит от содержимого или packetId. Любая ошибка в одном символе приведет к отказу в обслуживании.

Выяснив эти технические подробности и реализовав корректную сборку пакета, мы обеспечим надежную передачу данных из 1С в любую внешнюю систему, поддерживающую стандарт multipart/form-data.

← На главную