При интеграции 1С со сторонними веб-сервисами и API часто возникает задача отправки данных методом POST с передачей параметров в формате формы application/x-www-form-urlencoded. Типичная ошибка при такой реализации — отправка чистого XML-файла в теле запроса, тогда как веб-сервер ожидает именованные параметры формы (например, order_xml=<root>...</root>), из-за чего сервис возвращает ошибку о пустом документе (error_order_xml_empty).
Разберем причины возникновения этой проблемы и рассмотрим по шагам, как сформировать корректный HTTP-запрос в платформе 1С:Предприятие 8.3.
Проанализируем ситуацию, с которой сталкиваются разработчики при первой отправке запроса:
/UploadOrders?skey=...&order_xml=, а в тело запроса через метод УстановитьИмяФайлаТела помещается только чистый XML. В таком случае сервер не связывает содержимое файла с параметром order_xml, так как ожидает либо параметры в теле запроса (при application/x-www-form-urlencoded), либо данные как multipart/form-data.HTTPЗапрос не указан заголовок Content-Type, сервер не может понять, как интерпретировать входящий поток байтов.ТекстовыйДокумент создает избыточную нагрузку на дисковую подсистему и может приводить к ошибкам из-за добавления маркера последовательности байтов (BOM).Рассмотрим наиболее быстрый и надежный способ: сформируем 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.ПолучитьТелоКакСтроку();
Исключение
ВызватьИсключение "Ошибка при отправке запроса: " + ОписаниеОшибки();
КонецПопытки;
Если структура веб-сервиса требует передачу параметра авторизации 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Запрос);
Обратите внимание на ключевые особенности реализации интеграции:
УстановитьТелоИзСтроки обязательно передавайте третий параметр ИспользованиеByteOrderMark.НеИспользовать. Наличие невидимого символа метки BOM в начале тела запроса приводит к тому, что парсеры на стороне сервера не могут опознать имя первого параметра формы.<, >, &, =, пробелы) внутри application/x-www-form-urlencoded, обязательно экранируйте строку с помощью функции КодироватьСтроку, иначе веб-сервер расценит символы как разделители параметров.ЧРД=. в функции Формат) либо применять стандартную функцию XMLСтрока().Новый HTTPСоединение(Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL()).