Как реализовать отправку multipart/form-data запроса из 1С на веб-сервер

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

При интеграции 1С с внешними веб-сервисами часто возникает задача передачи файлов вместе с дополнительными параметрами. Стандартным протоколом для таких операций является multipart/form-data. В этой статье мы подробно разберем, как перенести логику отправки таких запросов, например, из среды C# в 1С, рассмотрим типичные ошибки с кодировками и изучим современные инструменты платформы 8.3.

Анализ структуры multipart-запроса

Прежде чем приступать к написанию кода, проанализируем, что представляет собой такой запрос. В отличие от обычного application/x-www-form-urlencoded, формат multipart позволяет разбивать тело сообщения на несколько независимых частей, каждая из которых имеет собственные заголовки и содержимое. Разберем основные компоненты:

  1. Boundary (Разделитель): Уникальная строка, которая отделяет одну часть данных от другой. Она указывается в заголовке Content-Type.
  2. Заголовки частей: Каждая часть (текстовое поле или файл) начинается с заголовка Content-Disposition, где указывается имя поля (name) и, если это файл, имя файла (filename).
  3. Тело части: Сами данные, отделенные от заголовков пустой строкой.
  4. Завершающий разделитель: Финальная строка, сигнализирующая об окончании запроса.

Рассмотрим, как реализовать формирование такого тела в 1С по шагам.

Способ 1: Ручное формирование тела запроса (универсальный метод)

Этот метод подходит для версий платформы ниже 8.3.15, а также помогает лучше понять структуру передаваемых данных. Рассмотрим ситуацию, когда нам нужно передать файл (например, CSV) и набор текстовых параметров, как в примере из сообщения автора темы.

Для начала подготовим уникальный разделитель и заголовки. Проанализируем пример кода:


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

// Формируем заголовки HTTP-запроса
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);

// Начинаем сборку тела сообщения
// Важно: в multipart-запросах используется перевод строки CRLF
ВК = Символы.ВК;
ПС = Символы.ПС;
CRLF = ВК + ПС;

ТелоЗапроса = "";

// Добавляем текстовый параметр "documentType"
ТелоЗапроса = ТелоЗапроса + "--" + Разделитель + CRLF;
ТелоЗапроса = ТелоЗапроса + "Content-Disposition: form-data; name=""documentType""" + CRLF + CRLF;
ТелоЗапроса = ТелоЗапроса + "WriteOffDocument" + CRLF;

// Добавляем файл
ТелоЗапроса = ТелоЗапроса + "--" + Разделитель + CRLF;
ТелоЗапроса = ТелоЗапроса + "Content-Disposition: form-data; name=""fileName""; filename=""Act123.txt""" + CRLF;
ТелоЗапроса = ТелоЗапроса + "Content-Type: application/vnd.ms-excel" + CRLF + CRLF;
ТелоЗапроса = ТелоЗапроса + СодержимоеФайлаТекстом + CRLF;

// Завершаем запрос
ТелоЗапроса = ТелоЗапроса + "--" + Разделитель + "--" + CRLF;

Важный нюанс: Как выяснил автор темы методом "научного тыка", кодировка текста играет решающую роль. Если сервер ожидает данные в формате ANSI (Windows-1251), использование стандартного UTF-8 приведет к тому, что сервер не сможет распарсить файл (ошибка "file is not specified"). Поэтому при установке тела запроса необходимо явно указывать кодировку:


HTTPЗапрос = Новый HTTPЗапрос(ПутьНаСервере, Заголовки);
// Используем Windows-1251 (ANSI), если сервер старый или специфический
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, "windows-1251");

Способ 2: Использование современных инструментов (Платформа 8.3.15+)

Начиная с версии 8.3.15, в 1С появились специализированные объекты для работы с двоичными данными и многокомпонентными потоками. Это избавляет от необходимости вручную склеивать строки, что особенно критично при передаче больших файлов, так как работа со строками потребляет много оперативной памяти.

Разберем использование объекта МногокомпонентныйПоток. Посмотрим на алгоритм:

  1. Создаем массив частей потока (объекты ЭлементМногокомпонентногоПотока).
  2. Для каждого элемента настраиваем заголовки.
  3. Помещаем данные (из файла или из строки) в каждый элемент.
  4. Создаем итоговый МногокомпонентныйПоток и передаем его в запрос.

Проанализируем пример кода для этого метода:


Разделитель = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");
ЧастиПотока = Новый Массив;

// Часть 1: Текстовый параметр
ЗаголовокТипа = Новый Соответствие();
ЗаголовокТипа.Вставить("Content-Disposition", "form-data; name=""documentType""");
ДанныеТипа = Новый ПотокВПамяти(ПолучитьДвоичныеДанныеИзСтроки("WriteOffDocument", КодировкаТекста.ANSI));
ЭлементТипа = Новый ЭлементМногокомпонентногоПотока(ЗаголовокТипа, ДанныеТипа);
ЧастиПотока.Добавить(ЭлементТипа);

// Часть 2: Файл
ЗаголовокФайла = Новый Соответствие();
ЗаголовокФайла.Вставить("Content-Disposition", "form-data; name=""fileName""; filename=""Act123.txt""");
ЗаголовокФайла.Вставить("Content-Type", "application/vnd.ms-excel");

// Читаем файл как поток
ДанныеФайла = Новый ФайловыйПоток("C:\data\import\Act123.txt", РежимОткрытияФайла.Открыть);
ЭлементФайла = Новый ЭлементМногокомпонентногоПотока(ЗаголовокФайла, ДанныеФайла);
ЧастиПотока.Добавить(ЭлементФайла);

// Собираем всё в один поток
ИтоговыйПоток = Новый МногокомпонентныйПоток(ЧастиПотока, Разделитель);

HTTPЗапрос = Новый HTTPЗапрос(Путь);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
HTTPЗапрос.УстановитьТелоИзПотока(ИтоговыйПоток);

Типичные ошибки и методы отладки

Выясним, на что стоит обратить внимание, если запрос не проходит или сервер возвращает ошибку 400 (Bad Request):

  1. Неправильные дефисы в Boundary: Запомните правило: в заголовке Content-Type разделитель пишется "как есть", но в самом теле запроса перед ним всегда ставятся два дефиса (--boundary), а в самом конце всего сообщения — два дефиса до и два после (--boundary--).
  2. Символы перевода строки: Стандарт HTTP требует использования CRLF (\r\n). Если вы используете только ПС (\n), многие веб-серверы (особенно под управлением Windows/IIS или старые Java-серверы) не увидят границы частей.
  3. BOM (Byte Order Mark): При использовании УстановитьТелоИзСтроки с кодировкой UTF-8, 1С может добавить невидимые символы в начало потока. Это часто "ломает" первый разделитель. Если сервер капризный, используйте формирование через ДвоичныеДанные.
  4. Порядок полей: Хотя формально порядок не важен, на практике некоторые обработчики на стороне сервера (например, на JSP, как в примере автора) требуют, чтобы сначала шли текстовые метаданные, а файлы передавались в последнюю очередь.

Для диагностики мы рекомендуем использовать инструменты типа Fiddler или HTTPAnalyzer. Они позволяют перехватить запрос от оригинальной программы (например, на C#) и сравнить его байт-в-байт с тем, что генерирует 1С. Как показал опыт автора темы, именно сравнение через отладчик помогло выявить разницу в кодировках и успешно завершить задачу.

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

← На главную