При разработке веб-сервисов (SOAP) на платформе 1С разработчики часто сталкиваются с неожиданным поведением: в операции веб-сервиса в качестве возвращаемого значения указывается тип Structure из стандартного пакета http://v8.1c.ru/8.1/data/core, однако фактически метод возвращает сериализованный массив или примитивное значение. При этом ни на стороне сервера, ни на стороне клиента 1С исключений не возникает. Выясним причину такого поведения платформы, проанализируем риски для внешних систем и разберем правильные способы организации контрактов веб-сервисов.
Рассмотрим ситуацию на конкретном примере. В свойствах операции веб-сервиса задекларирован возвращаемый тип Structure (пакет http://v8.1c.ru/8.1/data/core). В теле функции выполняется следующий код:
Функция ПолучитьДанные()
МассивДанных = Новый Массив;
МассивДанных.Добавить("Тест");
Возврат СериализаторXDTO.ЗаписатьXDTO(МассивДанных);
КонецФункции
На стороне клиента 1С при получении ответа через WS-прокси код успешно отрабатывает:
ОтветXDTO = Прокси.ПолучитьДанные();
Результат = СериализаторXDTO.ПрочитатьXDTO(ОтветXDTO);
// В переменной Результат оказывается Массив, а не Структура
Проанализируем, почему вызов завершается успешно:
ОбъектXDTO, помещает его в тело конверта и явно указывает его фактический тип в XML-атрибуте xsi:type (например, xsi:type="v8:Array").СериализаторXDTO ориентируется именно на фактический XML-атрибут xsi:type в полученном документе, а не на исходный WSDL-контракт операции. Поэтому десериализация восстанавливает именно тот объект, который был отправлен сервером.С точки зрения разработчиков платформы 1С это поведение считается штатным. Однако такой подход несет серьезные архитектурные риски при интеграции со сторонними системами.
Если вызывающей стороной выступает не 1С, а приложение на Java, .NET, PHP или C++, возникнут проблемы:
Structure в пространстве имен http://v8.1c.ru/8.1/data/core представляет собой список пар с ключами и универсальными значениями Value типа anyType. Для сторонних клиентов такой тип не генерирует удобный объект с именованными полями, что сильно усложняет разработку интеграции.Структура, Массив, ТаблицаЗначений). Значение обязательно должно быть приведено к ОбъектXDTO, ЗначениеXDTO или базовому типу Строка. Попытка вернуть напрямую прикладной объект вызовет ошибку несоответствия типов.Разберем эталонный способ построения SOAP веб-сервиса. Для обеспечения самодокументируемости и жесткого контракта необходимо описать собственные типы данных в дереве метаданных.
Выполним следующие шаги:
http://myshop.org/integration).ОтветОперации).xs:string, xs:int, xs:dateTime и др.).
Функция ВыполнитьЗапрос()
ТипОтвета = ФабрикаXDTO.Тип("http://myshop.org/integration", "ОтветОперации");
ОтветXDTO = ФабрикаXDTO.Создать(ТипОтвета);
ОтветXDTO.Код = 200;
ОтветXDTO.Сообщение = "Успешно";
ОтветXDTO.ДатаФормирования = ТекущаяДатаСеанса();
Возврат ОтветXDTO;
КонецФункции
Такой подход гарантирует, что контракт WSDL будет полностью соответствовать реальному ответу, а любые изменения в схеме данных будут видны разработчикам внешних систем автоматически.
Если веб-сервис по своей логике должен возвращать полиморфные данные (в зависимости от входных параметров — структуру, массив или скалярное значение), нельзя декларировать конкретный тип наподобие Structure. Разберем, как оформить такую операцию корректно:
anyType из пространства имен http://www.w3.org/2001/XMLSchema.СериализаторXDTO:
Функция ПолучитьДинамическиеДанные(ТипЗапроса)
Если ТипЗапроса = "Массив" Тогда
Данные = Новый Массив;
Данные.Добавить("Элемент 1");
Иначе
Данные = Новый Структура("Статус", "ОК");
КонецЕсли;
Возврат СериализаторXDTO.ЗаписатьXDTO(Данные);
КонецФункции
Указание типа anyType официально разрешает возвращать любой XML-тип в соответствии со спецификацией W3C, и сторонние валидаторы не будут считать такой ответ нарушением контракта.
Если жесткая схема XSD не требуется, а интеграция выполняется с веб-сайтом, мобильным приложением или микросервисом, наиболее удобным вариантом является передача форматированной строки JSON.
string (пространство имен http://www.w3.org/2001/XMLSchema).
Функция ПолучитьДанныеВФорматеJSON()
СтруктураОтвета = Новый Структура;
СтруктураОтвета.Вставить("Результат", Истина);
СтруктураОтвета.Вставить("Данные", Новый Массив);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураОтвета);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
Сторонняя система прочитает строку и легко преобразует ее в нативные структуры языка (например, в объекты JavaScript или массивы PHP) без необходимости парсинга сложных SOAP-оберток.
Если вся передача данных сводится к обмену JSON-строками без использования стандартов SOAP и WS-Security, целесообразно отказаться от веб-сервисов в пользу объекта конфигурации HTTP-сервисы.
HTTP-сервисы платформы 1С работают быстрее за счет отсутствия оверхеда XML-конвертов, позволяют работать со стандартными HTTP-методами (GET, POST, PUT, DELETE) и возвращать JSON напрямую в теле ответа с заголовком Content-Type: application/json.