Интеграция со сторонними сервисами по протоколу SOAP — частая задача в практике разработчика «1С:Предприятие 8». Традиционный подход с инициализацией веб-сервиса напрямую по сетевой ссылке через конструктор Новый WSОпределения("http://api.site.ru/service.wsdl") прост в реализации, но имеет существенные недостатки. Сетевые задержки, нестабильный интернет, падение удаленного сервера или блокировки могут сильно замедлить работу системы или вовсе заблокировать ключевые бизнес-процессы.
Для ускорения работы и повышения отказоустойчивости разработчики часто прибегают к логичному решению: сохраняют WSDL-описание во внутренний макет конфигурации (с типом «Двоичные данные»), а при необходимости инициализации выгружают его во временный файл на диск и передают путь к этому файлу в конструктор WSОпределения. Однако на этом этапе многие сталкиваются с загадочной ошибкой: платформа ругается на отсутствие файла, имя которого отличается от имени созданного временного файла. В этой статье мы подробно разберем, почему возникает эта проблема и как ее правильно решить несколькими способами.
Рассмотрим стандартную ситуацию. Разработчик выгружает двоичные данные из макета во временный файл с помощью метода ПолучитьИмяВременногоФайла("wsdl"). Платформа генерирует случайное уникальное имя в системном каталоге временных файлов, например: C:\Users\user\AppData\Local\Temp\v8_BF2A_2bb.wsdl. Файл успешно записывается на диск, но при попытке выполнить следующий код:
ОпределениеWS = Новый WSОпределения(ПутьКВременномуФайлу);
Платформа генерирует исключение:
«Ошибка при вызове конструктора (WSОпределения): При вызове веб-сервиса произошла ошибка. При создании описания сервиса произошла ошибка. : Файл не обнаружен 'C:\Users\user\AppData\Local\Temp\Service.wsdl'»
Проанализируем ситуацию: почему система ищет файл с именем Service.wsdl, если мы явно передали ей путь к файлу v8_BF2A_2bb.wsdl? Дело в том, что WSDL-документ — это сложная XML-структура, которая часто состоит не из одного файла, а собирается из нескольких связанных частей. Внутри основного файла WSDL почти всегда присутствуют директивы импорта внешних файлов или схем данных. Это могут быть теги следующего вида:
<wsdl:import namespace="..." location="Service.wsdl"/> — импорт другого файла описания сервиса.<xsd:import namespace="..." schemaLocation="Service.xsd"/> — импорт внешней XSD-схемы, описывающей типы данных.Когда платформа «1С:Предприятие 8» начинает парсить переданный ей файл v8_BF2A_2bb.wsdl, она натыкается на атрибут location (или schemaLocation) со значением "Service.wsdl". Поскольку этот путь является относительным, парсер пытается разрешить его относительно каталога, в котором находится базовый файл.
Базовый файл лежит в папке C:\Users\user\AppData\Local\Temp\, следовательно, 1С пытается найти импортируемый файл по пути C:\Users\user\AppData\Local\Temp\Service.wsdl. Так как на диске по этому пути ничего нет (ведь мы сохранили файл под случайным именем v8_BF2A_2bb.wsdl), платформа выдает закономерную ошибку о том, что файл не обнаружен.
---
Самый простой и быстрый способ обойти данное ограничение — отказаться от генерации случайного имени файла через ПолучитьИмяВременногоФайла(). Вместо этого мы должны принудительно записать файл из макета в каталог временных файлов под тем именем, которое жестко прописано в теле WSDL-файла (в атрибуте location).
Выясним точное имя файла, открыв наш WSDL-файл в любом текстовом редакторе и найдя директиву location. Предположим, там указано Service.wsdl. Реализуем этот алгоритм на встроенном языке 1С:
// Получаем путь к системному каталогу временных файлов
КаталогВременныхФайлов = КаталогВременныхФайлов();
// Формируем точный путь с ожидаемым именем файла
ФайлWSDL = КаталогВременныхФайлов + "Service.wsdl";
// Получаем двоичные данные из макета конфигурации
ПолученныйМакет = ПолучитьМакет("service_wsdl");
ПолученныйМакет.Записать(ФайлWSDL);
Попытка
// Инициализируем определения веб-сервиса из файла с корректным именем
ОпределениеWS = Новый WSОпределения(ФайлWSDL);
Исключение
ЗаписьЖурналаРегистрации("Интеграция.WS", УровеньЖурналаРегистрации.Ошибка,,,
"Ошибка создания WS-определений: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось инициализировать веб-сервис. Обратитесь к администратору.";
КонецПопытки;
// После успешного создания объекта определения файл на диске больше не нужен
Попытка
УдалитьФайлы(ФайлWSDL);
Исключение
// Файл может быть кратковременно заблокирован процессом чтения,
// поэтому оборачиваем удаление в Попытка-Исключение
КонецПопытки;
Этот метод отлично работает, если WSDL-структура ссылается сама на себя или импортирует только один файл, имя которого нам заранее известно и неизменно.
---
В реальных интеграционных проектах (например, при обмене с государственными информационными системами или крупными ERP-системами) WSDL-файл часто импортирует целый каскад внешних файлов схем данных (файлы с расширением .xsd). Если вы перенесете в макет 1С только основной .wsdl, но забудете про сопутствующие .xsd, платформа выдаст аналогичную ошибку.
Рассмотрим по шагам, как правильно организовать работу со множественными зависимостями:
Макет_WSDL, Макет_XSD_Types, Макет_XSD_Core).WSОпределения последовательно выгрузите все файлы в один и тот же временный каталог под их оригинальными именами.Посмотрим на пример практической реализации такой выгрузки:
КаталогВременныхФайлов = КаталогВременныхФайлов();
// Структура, сопоставляющая имена макетов и целевые имена файлов на диске
СоответствиеФайлов = Новый Соответствие;
СоответствиеФайлов.Вставить("Макет_WSDL", "main.wsdl");
СоответствиеФайлов.Вставить("Макет_XSD_Types", "types.xsd");
СоответствиеФайлов.Вставить("Макет_XSD_Core", "core.xsd");
// Выгружаем все файлы в один каталог
Для Каждого Элемент Из СоответствиеФайлов Цикл
Макет = ПолучитьМакет(Элемент.Ключ);
ИмяФайлаНаДиске = КаталогВременныхФайлов + Элемент.Значение;
Макет.Записать(ИмяФайлаНаДиске);
КонецЦикла;
// Инициализируем WSОпределения по главному файлу
ПутьКГлавномуФайлу = КаталогВременныхФайлов + "main.wsdl";
ОпределениеWS = Новый WSОпределения(ПутьКГлавномуФайлу);
// Производим зачистку всех временных файлов
Для Каждого Элемент Из СоответствиеФайлов Цикл
ПутьКФайлу = КаталогВременныхФайлов + Элемент.Value;
Попытка
УдалитьФайлы(ПутьКФайлу);
Исключение
// Игнорируем ошибки блокировки файлов операционной системой
КонецПопытки;
EndЦикла;
При таком подходе парсер платформы успешно найдет все необходимые схемы types.xsd и core.xsd в той же папке, где лежит main.wsdl, и построит корректную фабрику XDTO.
---
Если вам не хочется загромождать конфигурацию десятками макетов двоичных данных и писать сложную логику их одновременной выгрузки на диск, можно пойти по пути «слияния» всех зависимостей в один монолитный файл. Этот процесс в веб-разработке называется flattening (выравнивание).
Суть метода заключается в том, чтобы перенести все структуры данных из внешних файлов .xsd непосредственно внутрь самого WSDL-файла. Для этого:
<wsdl:types>.<xsd:import schemaLocation="..."/> вставьте внутрь секции полноценное описание схем <xsd:schema>...</xsd:schema>, скопировав их содержимое из соответствующих файлов XSD.Выполнить эту операцию можно вручную в любом продвинутом XML-редакторе (например, XMLSpy, Oxygen XML Editor) или воспользоваться бесплатными консольными утилитами для «выравнивания» WSDL. Полученный на выходе «плоский» WSDL-файл не будет иметь никаких внешних зависимостей. Его можно сохранять на диск под абсолютно любым случайным именем через ПолучитьИмяВременногоФайла() — он гарантированно прочитается платформой 1С без ошибок.
---
Иногда возникают ситуации, когда WSDL содержит ссылки на внешние интернет-ресурсы, доступ к которым у сервера «1С:Предприятие» ограничен настройками безопасности (например, закрыт доступ во внешнюю сеть файрволом). Если парсер 1С попытается разрешить внешние ссылки типа location="http://vendor-site.com/schemas/types.xsd", процесс завершится ошибкой таймаута.
В этом случае мы можем программно отредактировать текст WSDL перед тем, как отдавать его в конструктор WSОпределения. Проанализируем пример кода, который считывает WSDL как текст, удаляет или подменяет адреса внешних схем и записывает результат во временный файл:
// Считываем исходный текст WSDL-файла из макета
МакетWSDL = ПолучитьМакет("service_wsdl");
ИмяФайлаИсточника = ПолучитьИмяВременногоФайла("tmp");
МакетWSDL.Записать(ИмяФайлаИсточника);
ТекстWSDL = Новый ТекстовыйДокумент;
ТекстWSDL.Прочитать(ИмяФайлаИсточника);
СтроковыйТекст = ТекстWSDL.ПолучитьТекст();
// Производим замену внешних интернет-адресов схем на локальные файлы или относительные пути
// Например, если внешняя схема была скачана нами и лежит локально
СтроковыйТекст = СтрЗаменить(СтроковыйТекст,
"http://vendor-site.com/schemas/types.xsd",
"local_types.xsd");
// Записываем измененный текст в новый временный файл
ИмяФайлаДляЗагрузки = ПолучитьИмяВременногоФайла("wsdl");
ТекстWSDL.УстановитьТекст(СтроковыйТекст);
ТекстWSDL.Записать(ИмяФайлаДляЗагрузки);
// Выгружаем саму схему local_types.xsd, чтобы она была доступна парсеру в той же временной папке
КаталогВременныхФайлов = КаталогВременныхФайлов();
МакетСхемы = ПолучитьМакет("service_xsd");
МакетСхемы.Записать(КаталогВременныхФайлов + "local_types.xsd");
// Инициализируем WSОпределения
Попытка
ОпределениеWS = Новый WSОпределения(ИмяФайлаДляЗагрузки);
Исключение
ВызватьИсключение "Ошибка разбора измененного WSDL: " + ОписаниеОшибки();
КонецПопытки;
// Чистим временные файлы
УдалитьФайлы(ИмяФайлаИсточника);
УдалитьФайлы(ИмяФайлаДляЗагрузки);
УдалитьФайлы(КаталогВременныхФайлов + "local_types.xsd");
Этот гибкий подход позволяет динамически подстраивать конфигурацию под изменения сетевой инфраструктуры без необходимости полной переработки макетов.
---
Для того чтобы ваша интеграция работала стабильно, необходимо учитывать несколько критически важных особенностей платформы «1С:Предприятие 8» при работе с локальными XML-схемами:
<definitions> или <wsdl:definitions>. Если в начале файла будут присутствовать лишние комментарии, метаданные сторонних утилит или пробельные символы до объявления заголовка XML, платформа выдаст ошибку неверного формата файла.targetNamespace внутри корневого тега <xs:schema>. Если этот атрибут отсутствует, фабрика XDTO платформы 1С не сможет сопоставить типы данных и проигнорирует схему, что приведет к ошибкам при вызове методов веб-сервиса.Применяя описанные методики работы с локальными файлами определений, мы можем создавать быстрые, независимые от интернета и стабильные интеграционные решения на платформе «1С:Предприятие 8».