При интеграции 1С со сторонними веб-сервисами часто приходится переносить готовые примеры интеграции с других языков программирования, в частности с PHP (cURL). Рассмотрим типовые ошибки, с которыми сталкиваются разработчики при переносе кода на встроенный язык 1С, и разберем несколько способов отправки данных: через прямое HTTP-соединение, работу с файлами и через нативные механизмы SOAP/WSDL.
Проанализируем исходный пример кода на 1С и выясним основные причины, почему веб-сервер может возвращать ошибки или отклонять соединение:
HTTPСоединение необходимо передавать только доменное имя или IP-адрес сервера (без указания протокола https:// и без относительного пути к скрипту). Относительный путь к ресурсу передается в объекте HTTPЗапрос.HTTPСоединение необходимо явно передавать параметр защищенного соединения ЗащищенноеСоединениеOpenSSL и порт (обычно 443).Host на основе настроек соединения. Передача строки "request" вместо числового размера или дублирование системных заголовков приводит к ошибкам протокола HTTP.УстановитьТелоИзСтроки() по умолчанию добавляет метку порядка байтов (UTF-8 BOM), которую многие веб-сервисы и XML-парсеры на стороне PHP не могут корректно разобрать.Разберем правильный вариант формирования защищенного 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", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
Посмотрим на альтернативный вариант, когда для отправки большого объема данных формируется файл на диске. В этом случае платформе передается путь к файлу источника и файлу приемника ответа:
ИмяВходящегоФайла = ПолучитьИмяВременногоФайла("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);
Результат = ЧтениеОтвета.Прочитать();
ЧтениеОтвета.Закрыть();
Исключение
УдалитьФайлы(ИмяВходящегоФайла);
УдалитьФайлы(ИмяИсходящегоФайла);
ВызватьИсключение;
КонецПопытки;
УдалитьФайлы(ИмяВходящегоФайла);
УдалитьФайлы(ИмяИсходящегоФайла);
Если конечный сервис реализован по протоколу SOAP, более надежным решением является использование штатных механизмов 1С для работы с веб-сервисами. При динамическом чтении WSDL через WSОпределения разработчики нередко сталкиваются с ошибкой Extra content at the end of the document. Она возникает, когда веб-сервер отдает в конце документа WSDL скрытые пробелы, лишние переводы строк или текст предупреждений PHP.
Разберем способы устранения этой проблемы:
WS-ссылку и загружаем схему WSDL по URL или из локального файла. Статическая ссылка компилирует типы один раз на этапе разработки, что исключает ошибки динамического парсинга при каждом обращении.WSОпределения, скачиваем WSDL-файл на диск через HTTPСоединение, удаляем некорректные символы после закрывающего тега </wsdl:definitions> и создаем объект из локального файла.Пример вызова сервиса через статическую WS-ссылку:
// Использование предварительно добавленной WS-ссылки в дереве метаданных
Прокси = WSСсылки.ИнтеграцияHyundai.СоздатьWSПрокси("ИмяСервиса", "ИмяПорта");
РезультатОперации = Прокси.ИмяМетода(ПараметрыМетода);
Если по каким-либо причинам стандартные методы платформы не могут установить соединение (например, на старых релизах платформы с ограничениями по протоколам 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;
КонецЕсли;