Как правильно отправить XML файл с помощью multipart/form-data в 1С и исправить ошибки авторизации

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

В современной разработке на платформе 1С:Предприятие 8 часто возникает необходимость интеграции с внешними веб-сервисами через HTTP API. Одной из самых трудоемких задач является корректное формирование запроса в формате multipart/form-data. Часто разработчики сталкиваются с ситуацией, когда в сторонних инструментах, таких как Postman, запрос проходит успешно, а 1С возвращает неочевидные ошибки вроде "Not Allowed" или "403 Forbidden". В этой статье мы детально разберем, как правильно сконструировать такой запрос, проанализируем типичные ошибки в синтаксисе заголовков и изучим современные подходы к работе с бинарными данными.

Разбор проблемы: почему Postman работает, а 1С — нет?

Рассмотрим ситуацию, когда при идентичных, на первый взгляд, параметрах сервер отказывает в доступе именно запросу из 1С. Выясним причину на конкретном примере. Проанализируем фрагмент кода, где формируется заголовок запроса:


Заголовки = Новый Соответствие;  
Заголовки.Вставить("Storage-Token", "5d******99dff");
Заголовки.Вставить("Content-Type","multipart/form-data; boundary =" + Разделитель);

Проблема здесь кроется в строгом соблюдении стандартов протокола HTTP. В строке "multipart/form-data; boundary =" перед знаком равенства стоит лишний пробел. Для многих веб-серверов (например, на базе Nginx или специализированных API-шлюзов) это делает параметр boundary нечитаемым. Сервер не может найти разделитель в теле запроса, считает структуру данных нарушенной и возвращает ошибку доступа или метода, так как не может распознать части multipart. Посмотрим на правильный вариант написания:


Заголовки.Вставить("Content-Type","multipart/form-data; boundary=" + Разделитель);

Важно: Пробел после точки с запятой допустим, но вокруг знака "=" в параметре boundary его быть не должно. Это критический нюанс, который часто упускается при ручном формировании строк.

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

Разберем классический метод сборки тела запроса с использованием объекта ТекстовыйДокумент. Этот метод подходит для текстовых файлов (XML, JSON), но требует внимательности к каждому символу. Проанализируем последовательность действий:

  1. Генерируем уникальный разделитель (boundary).
  2. Устанавливаем правильные символы перевода строк (CRLF).
  3. Формируем блоки данных, разделяя их заголовками.
  4. Завершаем тело финальным разделителем с двумя дефисами в конце.

Посмотрим на пример реализации:


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

// Первая часть - файл
ТелоЗапроса.ДобавитьСтроку("--" + Разделитель);
ТелоЗапроса.ДобавитьСтроку("Content-Disposition: form-data; name=""file""; filename=""stocks.xml""");
ТелоЗапроса.ДобавитьСтроку("Content-Type: application/xml");
ТелоЗапроса.ДобавитьСтроку(""); // Пустая строка перед данными
ТелоЗапроса.ДобавитьСтроку(СтрXML);

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

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

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

Обратим внимание на свойство РазделительСтрок. Стандарт RFC требует использования последовательности CRLF. Если ваш сервер работает на Linux, а 1С настроена на стандартные системные разделители, это может привести к ошибке обработки. Всегда явно указывайте Символы.ВК + Символы.ПС.

Современный подход: использование потоков и бинарных данных

Метод формирования через ТекстовыйДокумент имеет существенный недостаток: он плохо подходит для передачи бинарных файлов (картинок, архивов) и может искажать кодировку. Начиная с версии платформы 8.3.10, мы рекомендуем использовать ПотокВПамяти и объект КопироватьДанные. Это позволит объединить текстовые заголовки и сырые двоичные данные без риска повреждения файла.

Рассмотрим, как это реализовать:


// Создаем поток для сборки тела
ПотокРезультат = Новый ПотокВПамяти();
ЗаписьДанных = Новый ЗаписьДанных(ПотокРезультат, КодировкаТекста.UTF8, , Ложь); // Ложь - без BOM

// Записываем начало
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""data.xml""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/xml");
ЗаписьДанных.ЗаписатьСтроку(""); // Разделитель между заголовком и данными

// Записываем само тело файла (если это ДвоичныеДанные)
ЗаписьДанных.Закрыть(); // Скидываем буфер текста в поток
ПотокФайла = ДвоичныеДанныеФайла.ОткрытьПотокДляЧтения();
КопироватьДанные(ПотокФайла, ПотокРезультат);
ПотокФайла.Закрыть();

// Снова открываем запись для финала
ЗаписьДанных = Новый ЗаписьДанных(ПотокРезультат, КодировкаТекста.UTF8, , Ложь);
ЗаписьДанных.ЗаписатьСтроку(""); // Завершающий перевод строки после данных файла
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--");
ЗаписьДанных.Закрыть();

// Получаем итоговые данные для запроса
ДвоичныеДанныеТела = ПотокРезультат.ЗакрытьИПолучитьДвоичныеДанные();
HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТела);

Этот метод гарантирует, что 1С не добавит в начало запроса невидимую метку BOM (Byte Order Mark), которая часто становится причиной отказа серверов принимать запрос. Использование КопироватьДанные напрямую в поток — это наиболее производительный и безопасный способ передачи файлов любого размера.

Диагностика и отладка: советы профессионалов

Если запрос все равно не проходит, проанализируем ситуацию с помощью "снифферов" трафика (например, Fiddler или Wireshark). Сравним "сырой" (raw) текст запроса из Postman и из 1С. Проверим следующие моменты:

  1. Заголовок Content-Length: 1С вычисляет его автоматически при использовании УстановитьТело.... Убедимся, что мы не переопределяем его вручную неправильным значением.
  2. URL ресурса: Обратим внимание на начальные слэши. Если путь в Postman выглядит как /~/upload, то и в объекте HTTPЗапрос параметр АдресРесурса должен начинаться с символа /. Это особенно актуально при тестировании запросов к ВетИС.
  3. Регистр заголовков: Хотя заголовки HTTP обычно нечувствительны к регистру, некоторые API требуют строгого написания Storage-Token или Content-Type, например, при подписи RSA с хешированием.
  4. Пустые строки: Между заголовками секции multipart и её телом обязательно должна быть одна пустая строка. Ошибка в количестве этих строк — частая причина 400-х ошибок.

В завершение подчеркнем: при работе с HTTP-запросами в 1С "дьявол кроется в деталях". Лишний пробел, отсутствие CRLF или наличие метки BOM могут полностью блокировать интеграцию. Используя современные объекты платформы и внимательно проверяя синтаксис заголовков, мы сможем построить надежный механизм обмена данными с любой внешней системой.

← На главную