При интеграции сторонних систем с 1С через SOAP/REST веб-сервисы разработчики часто сталкиваются с ситуацией, когда одни объекты конфигурации создаются без проблем, а при попытке программно создать другие документы сервер мгновенно возвращает 500 Internal Server Error. При этом стандартная конструкция Попытка ... Исключение внутри метода веб-сервиса не перехватывает исключение, а журнал регистрации остается пустым.
В этой статье мы подробно разберем, как локализовать подобную ошибку, настроить подробный вывод сообщений об ошибках в IIS и исправить проблемы контекста исполнения кода на стороне 1С.
По умолчанию веб-сервер IIS при возникновении критических сбоев в рабочем процессе 1С скрывает подробности и отдаёт клиенту лишь обобщённый статус HTTP 500. Чтобы увидеть реальный текст ошибки (SOAP Fault) и стек вызова, необходимо настроить параметр отображения ошибок виртуального приложения.
Рассмотрим пошагово порядок настройки в менеджере служб IIS:
Имя сервера -> Сайты -> Default Web Site -> [Имя виртуального приложения].После этой настройки веб-сервис вместо обезличенной ошибки 500 начнет возвращать полноценное SOAP-сообщение с текстом исключения, возникшего на стороне 1С.
Проанализируем пример текста ошибки, который возвращается в SOAP Fault после включения детализации:
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Неизвестная ошибка. {ОбщийМодуль.ОбщийДляНШ(9,118)}: Переменная не определена (РабочаяДата)</faultstring>
</soap:Fault>
Или другой вариант ошибки при создании документа:
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Неизвестная ошибка. {Документ.ЗаказПоставщику(297,53)}: Переменная не определена (ФормированиеПечатныхФорм)</faultstring>
</soap:Fault>
Выясним причину такого поведения. Сеанс веб-сервиса выполняется строго в серверном контексте. При выполнении кода создания нового документа (например, Документы.ЗаказПокупателя.СоздатьДокумент()) платформа производит синтаксическую проверку и компиляцию модуля объекта, модуля менеджера и связанных общих модулей.
Если в этих модулях присутствуют обращения к клиентским переменным или модулям, происходят критические сбои:
РабочаяДата: является элементом глобального контекста клиентского приложения и полностью отсутствует в серверных сеансах, фоновых заданиях и веб-сервисах.ФормированиеПечатныхФорм) не имеет установленного флага Сервер в свойствах или предназначен только для работы на клиенте, обращение к нему из серверного контекста приводит к ошибке компиляции «Переменная не определена».Так как синтаксическая ошибка происходит на этапе компиляции модуля до начала фактического выполнения кода процедуры, конструктор Попытка ... Исключение внутри метода веб-сервиса не успевает отработать, а запись в журнал регистрации не производится.
Разберем способы устранения обнаруженных проблем в конфигурации 1С.
Шаг 1. Разделение клиентской и серверной логики директивами компиляции
Если в модуле объекта документа или общем модуле содержится код, обращающийся к интерфейсу или клиентским переменным, оборачиваем его в инструкции препроцессора:
#Если Клиент Тогда
// Код, выполняемый только на клиенте
ТекущаяДатаДокумента = РабочаяДата;
#Иначе
// Серверный контекст (включая веб-сервисы)
ТекущаяДатаДокумента = ТекущаяДатаСеанса();
#КонецЕсли
Шаг 2. Замена глобальной переменной РабочаяДата
В серверном коде вместо РабочаяДата необходимо использовать функцию ТекущаяДата() или ТекущаяДатаСеанса(). Если бизнес-логика требует использовать специфическую рабочую дату пользователя, её следует передавать явным образом в параметрах вызова метода веб-сервиса.
Шаг 3. Проверка свойств общих модулей
В конфигураторе найдем общие модули, на которые ссылается код документа, и проверим их свойства:
Посмотрим на исходный код получения менеджера объекта из темы:
// Нерекомендуемый вариант: использование динамического Вычислить()
Спр = Вычислить("Документы." + name);
НовыйОбъект = Спр.СоздатьДокумент();
Использование функции Вычислить() ухудшает читаемость кода, затрудняет отладку и работает медленнее. Рекомендуется использовать прямое обращение к коллекциям метаданных через квадратные скобки:
// Рекомендуемый вариант: прямое обращение к коллекции по имени
МенеджерДокумента = Документы[name];
НовыйОбъект = МенеджерДокумента.СоздатьДокумент();
Если тип объекта заранее неизвестен, универсальную функцию создания объекта можно реализовать следующим образом:
Функция СоздатьНовыйОбъект(ИмяТипа, ИмяОбъекта)
НовыйОбъект = Неопределено;
Если ИмяТипа = "Справочник" Тогда
НовыйОбъект = Справочники[ИмяОбъекта].СоздатьЭлемент();
ИначеЕсли ИмяТипа = "Документ" Тогда
НовыйОбъект = Документы[ИмяОбъекта].СоздатьДокумент();
Иначе
ВызватьИсключение "Неподдерживаемый тип объекта: " + ИмяТипа;
КонецЕсли;
Возврат НовыйОбъект;
КонецФункции
Применение этого подхода совместно с разделением клиентского и серверного контекста гарантирует стабильную работу веб-сервисов и корректную обработку SOAP-запросов.