Как правильно передать XML в веб-сервис из 1С: решаем проблемы типизации и кодировки

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

При интеграции систем часто возникает ситуация, когда сформированный в 1С XML-файл успешно проходит проверку в сторонних инструментах вроде SoapUI, но при попытке отправить его через WSПрокси веб-сервис возвращает ошибку. Чаще всего разработчики сталкиваются с тем, что принимающая сторона видит данные как блок CDATA или сообщает о несоответствии типов данных. В этой статье мы подробно разберем причины такого поведения и рассмотрим проверенные способы корректной передачи данных.

Анализ проблемы: почему "просто строка" не подходит?

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


ЧтениеXML = Новый ТекстовыйДокумент;
ЧтениеXML.Прочитать(ПутьКФайлу, "UTF-8");
ДанныеДляОтправки = ЧтениеXML.ПолучитьТекст();

РезультатОтправки = Прокси.ИмяМетода(ДанныеДляОтправки);

Проанализируем, что происходит "под капотом". Объект WSПрокси при отправке данных пытается автоматически определить тип параметра. Если в описании WSDL указано, что метод ждет строку, платформа 1С выполнит экранирование спецсимволов. Все символы < превратятся в <, а > в >. В итоге веб-сервис получит не структуру XML, а обычный текст, который не сможет распарсить. Выясним, как заставить систему передать данные именно в том виде, в котором их ждет удаленный сервер.

Решение №1: Использование Фабрики XDTO для явной типизации

Это самый надежный способ при работе через WSПрокси. Чтобы платформа не искажала содержимое строки, нам нужно явно указать тип данных, используя ФабрикаXDTO. Это гарантирует, что XML-структура внутри строки будет воспринята сервисом корректно.

Разберем по шагам процесс создания типизированного параметра:

  1. Создаем объект WSОпределения для получения метаданных сервиса.
  2. Инициализируем WSПрокси.
  3. Используем стандартное пространство имен XMLSchema для определения типа "string".
  4. Создаем объект XDTO, который "обернет" нашу XML-строку.

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


// 1. Инициализация подключения
Определения = Новый WSОпределения(МестоположениеWSDL);
Прокси = Новый WSПрокси(Определения, ПространствоИмен, ИмяСервиса, ИмяТочки);

// 2. Явное указание типа данных через Фабрику XDTO
// Используем URI пространства имен XMLSchema для базовых типов
ТипПараметра = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "string");

// 3. Создание значения параметра на основе нашей XML-строки
ЗначениеПараметра = ФабрикаXDTO.Создать(ТипПараметра, СтрокаXMLДанных);

// 4. Вызов метода сервиса
Результат = Прокси.ИмяМетода(ЗначениеПараметра);

Важный момент: использование метода ФабрикаXDTO.Создать() позволяет передать строку "как есть", без лишних преобразований платформы, которые могут привести к ошибке формата на стороне получателя.

Проблема BOM (Byte Order Mark) и корректное чтение файлов

Проанализируем еще одну скрытую угрозу. При использовании объекта ТекстовыйДокумент для чтения XML-файла, в начало строки может попасть невидимый символ BOM. Многие веб-сервисы (особенно написанные на языках Java, PHP или Python) крайне чувствительны к лишним символам перед открывающим тегом <?xml...?> и выдают ошибку парсинга.

Чтобы избежать этой проблемы, рекомендуем использовать объект ЗаписьXML напрямую в строку, минуя промежуточное сохранение в файл и использование текстовых редакторов:


ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь); // Ложь отключает BOM
ЗаписьXML.УстановитьСтроку(ПараметрыЗаписи);

// Здесь формируем структуру XML через ЗаписьXML...
// ЗаписьXML.ЗаписатьНачалоЭлемента("Root");
// ...

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

Такой подход гарантирует "чистоту" данных. Если же файл уже существует, используйте объект ЧтениеXML, который корректно обрабатывает заголовки кодировок.

Решение №2: Отправка через HTTPЗапрос (ручное формирование SOAP)

Если работа через WSПрокси вызывает непреодолимые сложности (например, из-за специфических требований сервиса к заголовкам или сложной структуры WSDL), мы можем воспользоваться объектом HTTPЗапрос. В этом случае мы сами формируем SOAP-конверт.

Посмотрим на пример формирования такого запроса:


// Формируем текстовый шаблон SOAP-конверта
ТекстЗапроса = 
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
|   <soapenv:Header/>
|   <soapenv:Body>
|       <m:ИмяМетода xmlns:m=""http://uri-сервиса"">
|           " + СтрокаXMLДанных + "
|       </m:ИмяМетода>
|   </soapenv:Body>
|</soapenv:Envelope>";

Соединение = Новый HTTPСоединение(АдресСервера, , , , , , Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос(ОтносительныйПутьКСервису);

// Обязательно указываем правильный Content-Type
Запрос.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
// Многим сервисам необходим заголовок SOAPAction
Запрос.Заголовки.Вставить("SOAPAction", "http://uri-сервиса/ИмяМетода");

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

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

Этот метод дает полный контроль над передаваемыми данными. Мы можем точно определить, где будет находиться наш XML и как он будет экранирован (или не экранирован вовсе).

Инструменты отладки и проверки

Когда мы сталкиваемся с неочевидным поведением WSПрокси, крайне полезно увидеть, что именно уходит в сеть. Проанализируем инструменты, которые в этом помогут:

Подводя итог, отметим: в большинстве случаев для успешной передачи XML достаточно использовать Фабрику XDTO для явного указания типа данных. Это избавляет от необходимости вручную формировать HTTP-пакеты и позволяет использовать все преимущества типизации платформы 1С.

← На главную