Как переписать отправку POST-запроса с XML из PHP cURL в 1С:Предприятие

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

При интеграции 1С со сторонними веб-сервисами часто приходится переносить готовые примеры интеграции с других языков программирования, в частности с PHP (cURL). Рассмотрим типовые ошибки, с которыми сталкиваются разработчики при переносе кода на встроенный язык 1С, и разберем несколько способов отправки данных: через прямое HTTP-соединение, работу с файлами и через нативные механизмы SOAP/WSDL.

Типичные ошибки при переносе cURL-запроса в 1С

Проанализируем исходный пример кода на 1С и выясним основные причины, почему веб-сервер может возвращать ошибки или отклонять соединение:

  1. Некорректное разделение адреса сервера и ресурса: в конструктор объекта HTTPСоединение необходимо передавать только доменное имя или IP-адрес сервера (без указания протокола https:// и без относительного пути к скрипту). Относительный путь к ресурсу передается в объекте HTTPЗапрос.
  2. Отсутствие настройки SSL: если запрос выполняется по защищенному протоколу HTTPS, в конструктор HTTPСоединение необходимо явно передавать параметр защищенного соединения ЗащищенноеСоединениеOpenSSL и порт (обычно 443).
  3. Ручное указание заголовков Host и Content-Length: платформа 1С автоматически рассчитывает длину тела запроса и формирует заголовок Host на основе настроек соединения. Передача строки "request" вместо числового размера или дублирование системных заголовков приводит к ошибкам протокола HTTP.
  4. Наличие BOM-символов в строке XML: метод УстановитьТелоИзСтроки() по умолчанию добавляет метку порядка байтов (UTF-8 BOM), которую многие веб-сервисы и XML-парсеры на стороне PHP не могут корректно разобрать.

Способ 1. Отправка POST-запроса с телом из строки через HTTPСоединение

Разберем правильный вариант формирования защищенного HTTP-соединения и отправки XML-строки на сервер. Рассмотрим код:


// 1. Формируем тело XML-запроса
ТекстXML = "<?xml version='1.0' encoding='utf-8'?>" + ТекстЭкспорта;

// 2. Настраиваем заголовки
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Заголовки.Вставить("User-Agent", "BITRIX SOAP Client");

// 3. Создаем HTTP-запрос с указанием относительного пути к ресурсу
ОтносительныйПуть = "/wsdl/post.php";
HTTPЗапрос = Новый HTTPЗапрос(ОтносительныйПуть, Заголовки);

// Исключаем добавление BOM-символов при установке тела запроса
HTTPЗапрос.УстановитьТелоИзСтроки(ТекстXML, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

// 4. Инициализируем защищенное HTTPS-соединение
Сервер = "hpromise.hyundai.ru";
Порт = 443;
SSL = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Сервер, Порт,,,, 30, SSL);

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

Способ 2. Отправка запроса через временные файлы

Посмотрим на альтернативный вариант, когда для отправки большого объема данных формируется файл на диске. В этом случае платформе передается путь к файлу источника и файлу приемника ответа:


ИмяВходящегоФайла = ПолучитьИмяВременногоФайла("xml");
ИмяИсходящегоФайла = ПолучитьИмяВременногоФайла("xml");

// Сохраняем XML без BOM во временный файл
ЗаписьXML = Новый ЗаписьТекста(ИмяВходящегоФайла, КодировкаТекста.UTF8,, ИспользованиеByteOrderMark.НеИспользовать);
ЗаписьXML.Записать("<?xml version='1.0' encoding='utf-8'?>" + ТекстЭкспорта);
ЗаписьXML.Закрыть();

Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
Заголовки.Вставить("User-Agent", "BITRIX SOAP Client");

Сервер = "hpromise.hyundai.ru";
ОтносительныйПуть = "/wsdl/post.php";
SSL = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(Сервер, 443,,,, 30, SSL);

Попытка
    HTTPСоединение.ОтправитьДляОбработки(ИмяВходящегоФайла, ОтносительныйПуть, ИмяИсходящегоФайла, Заголовки);
    
    ЧтениеОтвета = Новый ЧтениеТекста(ИмяИсходящегоФайла, КодировкаТекста.UTF8);
    Результат = ЧтениеОтвета.Прочитать();
    ЧтениеОтвета.Закрыть();
Исключение
    УдалитьФайлы(ИмяВходящегоФайла);
    УдалитьФайлы(ИмяИсходящегоФайла);
    ВызватьИсключение;
КонецПопытки;

УдалитьФайлы(ИмяВходящегоФайла);
УдалитьФайлы(ИмяИсходящегоФайла);

Способ 3. Работа через SOAP и WS-ссылки платформы 1С

Если конечный сервис реализован по протоколу SOAP, более надежным решением является использование штатных механизмов 1С для работы с веб-сервисами. При динамическом чтении WSDL через WSОпределения разработчики нередко сталкиваются с ошибкой Extra content at the end of the document. Она возникает, когда веб-сервер отдает в конце документа WSDL скрытые пробелы, лишние переводы строк или текст предупреждений PHP.

Разберем способы устранения этой проблемы:

  1. Создание статической WS-ссылки в конфигураторе: в дереве метаданных добавляем новую WS-ссылку и загружаем схему WSDL по URL или из локального файла. Статическая ссылка компилирует типы один раз на этапе разработки, что исключает ошибки динамического парсинга при каждом обращении.
  2. Предварительная загрузка и очистка WSDL: если требуется динамическое создание WSОпределения, скачиваем WSDL-файл на диск через HTTPСоединение, удаляем некорректные символы после закрывающего тега </wsdl:definitions> и создаем объект из локального файла.

Пример вызова сервиса через статическую WS-ссылку:


// Использование предварительно добавленной WS-ссылки в дереве метаданных
Прокси = WSСсылки.ИнтеграцияHyundai.СоздатьWSПрокси("ИмяСервиса", "ИмяПорта");
РезультатОперации = Прокси.ИмяМетода(ПараметрыМетода);

Способ 4. Отправка через COM-объект WinHttp

Если по каким-либо причинам стандартные методы платформы не могут установить соединение (например, на старых релизах платформы с ограничениями по протоколам TLS), можно применить системный COM-объект:


HTTP = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
HTTP.Open("POST", "https://hpromise.hyundai.ru/wsdl/post.php", Ложь);
HTTP.SetRequestHeader("Content-Type", "text/xml; charset=utf-8");
HTTP.SetRequestHeader("User-Agent", "BITRIX SOAP Client");
HTTP.Send(ТекстXML);

Если HTTP.Status = 200 Тогда
    Результат = HTTP.ResponseText;
Иначе
    ВызватьИсключение "Ошибка COM WinHttp: " + HTTP.Status + " " + HTTP.StatusText;
КонецЕсли;
← На главную