Как правильно отправить POST-запрос с телом XML и параметрами формы из 1С?

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

При интеграции 1С со сторонними веб-сервисами и API часто возникает задача отправки данных методом POST с передачей параметров в формате формы application/x-www-form-urlencoded. Типичная ошибка при такой реализации — отправка чистого XML-файла в теле запроса, тогда как веб-сервер ожидает именованные параметры формы (например, order_xml=<root>...</root>), из-за чего сервис возвращает ошибку о пустом документе (error_order_xml_empty).

Разберем причины возникновения этой проблемы и рассмотрим по шагам, как сформировать корректный HTTP-запрос в платформе 1С:Предприятие 8.3.

Выясним причину ошибки

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

  1. Несоответствие структуры тела запроса формату: В строке URL указывается /UploadOrders?skey=...&order_xml=, а в тело запроса через метод УстановитьИмяФайлаТела помещается только чистый XML. В таком случае сервер не связывает содержимое файла с параметром order_xml, так как ожидает либо параметры в теле запроса (при application/x-www-form-urlencoded), либо данные как multipart/form-data.
  2. Отсутствие необходимых HTTP-заголовков: Если в объекте HTTPЗапрос не указан заголовок Content-Type, сервер не может понять, как интерпретировать входящий поток байтов.
  3. Использование лишних дисковых операций: Сохранение XML во временный файл и последующее чтение через ТекстовыйДокумент создает избыточную нагрузку на дисковую подсистему и может приводить к ошибкам из-за добавления маркера последовательности байтов (BOM).

Решение 1: Формирование строки запроса в памяти и передача через application/x-www-form-urlencoded

Рассмотрим наиболее быстрый и надежный способ: сформируем XML-строку напрямую в оперативной памяти без создания промежуточных файлов на диске, добавим параметр формы и передадим данные в запрос.

Разберем по шагам реализацию этого метода:


// 1. Формируем XML-документ непосредственно в строковую переменную
Запись = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("utf-8");
Запись.УстановитьСтроку(ПараметрыЗаписи);
Запись.ЗаписатьОбъявлениеXML();

Запись.ЗаписатьНачалоЭлемента("root");
Запись.ЗаписатьНачалоЭлемента("d");
Запись.ЗаписатьАтрибут("id", XMLСтрока(Контрагент.ID_pharmcenter_kz));

Для Каждого Стр Из Таблица Цикл
    Если ПустаяСтрока(Стр.ID_Товара) Тогда 
        Продолжить;
    КонецЕсли;
    
    Запись.ЗаписатьНачалоЭлемента("i");
    Запись.ЗаписатьАтрибут("id", XMLСтрока(Стр.ID_Товара));
    Запись.ЗаписатьАтрибут("count", Формат(Стр.Количество, "ЧДЦ=; ЧГ=0"));
    Запись.ЗаписатьАтрибут("expired", Формат(Стр.СрокГодности, "ДФ=dd.MM.yyyy"));
    Запись.ЗаписатьАтрибут("price", Формат(Стр.Цена, "ЧДЦ=2; ЧН=0; ЧГ=0; ЧРД=."));
    Запись.ЗаписатьКонецЭлемента();
КонецЦикла;

Запись.ЗаписатьКонецЭлемента(); // d
Запись.ЗаписатьКонецЭлемента(); // root

ТекстXML = Запись.Закрыть();

// 2. Рассчитываем MD5-хэш для авторизации
Если ПустаяСтрока(ПереданныйХеш) Тогда 
    Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
    Хеш.Добавить(СокрЛП(Пользователь) + "+" + СокрЛП(Пароль));
    ХешТекст = СтрЗаменить(НРег(Хеш.ХешСумма), " ", "");
Иначе
    ХешТекст = ПереданныйХеш;
КонецЕсли;

// 3. Формируем тело запроса и выполняем отправку
Сервер = "pharmcenter.kz";
Ресурс = "/External1CDirectory/UploadOrders";

// При передаче параметров формы данные должны быть закодированы
ТекстТела = "skey=" + ХешТекст + "&order_xml=" + КодироватьСтроку(ТекстXML, СпособКодированияСтроки.КодировкаURL, КодировкаТекста.UTF8);

Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");

HTTPЗапрос = Новый HTTPЗапрос(Ресурс, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТекстТела, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

HTTPСоединение = Новый HTTPСоединение(Сервер);

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

Решение 2: Отправка через файл тела с заголовком URL-Encoded

Если структура веб-сервиса требует передачу параметра авторизации skey в строке адреса (Query String), а параметр order_xml — в теле запроса, можно использовать отправку с явным указанием префикса формы в начале тела:


// Формируем текст тела с именем параметра
НачалоТекста = "order_xml=";
ТекстДляОтправки = НачалоТекста + ТекстXML;

Сервер = "pharmcenter.kz";
ТекстЗапроса = "/External1CDirectory/UploadOrders?skey=" + ХешТекст;

Заголовки = Новый Соответствие;    
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");

HTTPЗапрос = Новый HTTPЗапрос(ТекстЗапроса, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТекстДляОтправки, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

HTTPСоединение = Новый HTTPСоединение(Сервер);
ОтветHTTP = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

Важные рекомендации при работе с HTTP-запросами в 1С

Обратите внимание на ключевые особенности реализации интеграции:

  1. Отключение Byte Order Mark (BOM): При вызове метода УстановитьТелоИзСтроки обязательно передавайте третий параметр ИспользованиеByteOrderMark.НеИспользовать. Наличие невидимого символа метки BOM в начале тела запроса приводит к тому, что парсеры на стороне сервера не могут опознать имя первого параметра формы.
  2. Использование URL-кодирования: Передавая XML или строки со спецсимволами (<, >, &, =, пробелы) внутри application/x-www-form-urlencoded, обязательно экранируйте строку с помощью функции КодироватьСтроку, иначе веб-сервер расценит символы как разделители параметров.
  3. Форматирование чисел: В русской региональной настройке числовые значения форматируются с запятой в качестве разделителя дробной части. Для веб-сервисов рекомендуется передавать точку (параметр ЧРД=. в функции Формат) либо применять стандартную функцию XMLСтрока().
  4. Защищенные соединения (HTTPS): Если целевой адрес работает по безопасному протоколу, инициализируйте соединение с указанием порта 443 и объекта защиты: Новый HTTPСоединение(Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL()).
← На главную