Передача сложных прикладных объектов платформы 1С, таких как ТабличныйДокумент, через механизм веб-сервисов часто вызывает затруднения у разработчиков. Типичный сценарий: на сервере формируется печатная форма или отчет, который необходимо передать клиенту (другой базе 1С или внешней системе). Однако при попытке вернуть этот объект напрямую из функции веб-сервиса платформа генерирует критическую ошибку SOAP: "Обязательное возвращаемое значение не задано" (Client-side error). Получатель на стороне клиента видит результат как Неопределено.
В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем внутренние механизмы сериализации платформы 1С и рассмотрим три эффективных способа корректной и быстрой передачи табличного документа через веб-сервис.
При попытке передать объект типа ТабличныйДокумент напрямую, платформа 1С пытается выполнить его неявную (автоматическую) сериализацию в формат XML, сопоставляя тип со встроенными типами XDTO. В стандартах 1С тип, соответствующий табличному документу, находится в пространстве имен http://v8.1c.ru/8.2/data/spreadsheet и называется SpreadsheetDocument.
Однако автоматическая сериализация часто дает сбой, если в настройках веб-сервиса некорректно импортирован соответствующий пакет схем или нарушена структура сопоставления типов данных в веб-сервисе. В результате сбоя сериализатора платформа завершает выполнение функции без отправки сформированного тела SOAP-ответа. Клиент получает пустой XML, что и вызывает ошибку "Обязательное возвращаемое значение не задано", так как схема веб-сервиса строго требует наличия возвращаемого элемента.
Давайте пошагово рассмотрим способы решения этой проблемы.
Для того чтобы обойти ограничение неявного приведения типов, мы можем принудительно сериализовать наш табличный документ в объект XDTO на стороне веб-сервиса, а на стороне клиента выполнить обратную операцию (десериализацию).
Рассмотрим пример кода функции веб-сервиса на стороне сервера:
Функция GetApprovalSheet_BusinessProcess(ID_BusinessProcess)
// Получаем ссылку на бизнес-процесс по переданному GUID
БП = БизнесПроцессы.Согласование.ПолучитьСсылку(Новый УникальныйИдентификатор(ID_BusinessProcess));
// Формируем табличный документ с помощью экспортного метода
ТабличныйДокумент = БизнесПроцессы.Согласование.ЛистСогласования(ОбщегоНазначенияСервер.ЗначениеВМассиве(БП), Новый СписокЗначений);
// Принудительно сериализуем объект 1С в тип XDTO
ОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(ТабличныйДокумент);
Возврат ОбъектXDTO;
КонецФункции
В настройках веб-сервиса для возвращаемого значения данной операции необходимо указать тип SpreadsheetDocument из пространства имен http://v8.1c.ru/8.2/data/spreadsheet.
Теперь посмотрим, как обработать полученный ответ на стороне клиента-получателя (в другой базе 1С):
// Создаем прокси для обращения к веб-сервису
WSПрокси = ИнтеграцияС1СДокументооборот.СоздатьProxy();
// Вызываем метод веб-сервиса
ОтветXDTO = WSПрокси.GetApprovalSheet_BusinessProcess(ГУИД_БП);
Если ОтветXDTO <> Неопределено Тогда
// Читаем объект XDTO обратно в тип ТабличныйДокумент
ТабличныйДокумент = СериализаторXDTO.ПрочитатьXDTO(ОтветXDTO);
// Отображаем документ пользователю или отправляем на печать
ТабличныйДокумент.Показать("Лист согласования");
КонецЕсли;
Важный нюанс: Этот способ отлично работает при интеграции систем на платформе 1С. Однако у него есть существенный недостаток — низкая производительность. XML-структура типа SpreadsheetDocument детально описывает абсолютно каждую ячейку, ее границы, шрифт, цвет и объединения. Для больших отчетов размер XML-файла может составлять десятки мегабайт, что приведет к долгой отправке по сети и повышенному расходу оперативной памяти.
Если интеграция происходит исключительно между информационными базами 1С, то наиболее эффективным и быстрым способом будет передача табличного документа через ХранилищеЗначения.
При использовании этого подхода платформа автоматически сжимает табличный документ алгоритмом ZIP/Deflate и преобразует его в бинарную строку формата Base64. Объем передаваемых данных сокращается в 10–20 раз по сравнению со стандартным XML-описанием XDTO.
Давайте реализуем этот подход. Настроим тип возвращаемого значения операции веб-сервиса как ValueStorage (пространство имен http://v8.1c.ru/8.1/data/core).
Код функции веб-сервиса на стороне сервера:
Функция GetApprovalSheet_ValueStorage(ID_BusinessProcess)
БП = БизнесПроцессы.Согласование.ПолучитьСсылку(Новый УникальныйИдентификатор(ID_BusinessProcess));
ТабличныйДокумент = БизнесПроцессы.Согласование.ЛистСогласования(ОбщегоНазначенияСервер.ЗначениеВМассиве(БП), Новый СписокЗначений);
// Помещаем табличный документ в ХранилищеЗначения для автоматического сжатия
Возврат Новый ХранилищеЗначения(ТабличныйДокумент);
КонецФункции
Код получения и распаковки табличного документа на клиенте:
WSПрокси = ИнтеграцияС1СДокументооборот.СоздатьProxy();
// Получаем объект ХранилищеЗначения через веб-сервис
ОтветХранилище = WSПрокси.GetApprovalSheet_ValueStorage(ГУИД_БП);
Если ТипЗнч(ОтветХранилище) = Тип("ХранилищеЗначения") Тогда
// Извлекаем наш исходный табличный документ
ТабличныйДокумент = ОтветХранилище.Получить();
ТабличныйДокумент.Показать("Лист согласования");
КонецЕсли;
Что делать, если принимающей стороной выступает мобильное приложение, корпоративный портал или внешняя ERP-система не на платформе 1С? Сторонние приложения не смогут распознать структуру пакетов 1С SpreadsheetDocument или ValueStorage.
В таких случаях рекомендуется сохранять табличный документ на сервере в общепринятый открытый формат (например, PDF или XLSX), считывать его в двоичные данные и возвращать в формате base64Binary (пространство имен http://www.w3.org/2001/XMLSchema).
Проанализируем пример кода на сервере:
Функция GetApprovalSheet_AsPDF(ID_BusinessProcess)
БП = БизнесПроцессы.Согласование.ПолучитьСсылку(Новый УникальныйИдентификатор(ID_BusinessProcess));
ТабличныйДокумент = БизнесПроцессы.Согласование.ЛистСогласования(ОбщегоНазначенияСервер.ЗначениеВМассиве(БП), Новый СписокЗначений);
// Получаем имя временного файла на сервере
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
// Записываем табличный документ в файл формата PDF
ТабличныйДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);
// Читаем файл в объект ДвоичныеДанные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
// Удаляем временный файл с диска сервера после прочтения в память
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
ЗаписьЖурналаРегистрации("Веб-сервисы", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось удалить временный файл: " + ИмяВременногоФайла);
КонецПопытки;
Возврат ДвоичныеДанныеФайла;
КонецФункции
На стороне клиента (даже если это веб-сайт на PHP/Python или внешняя система) полученная Base64-строка легко декодируется в стандартный файл PDF, готовый для отображения пользователю на любом устройстве.
Для наглядности сравним все три рассмотренных варианта передачи данных, чтобы вы могли выбрать наиболее подходящий под ваши задачи архитектурный подход:
Используя явную сериализацию или упаковку в двоичные форматы, вы гарантированно избежите ошибок разбора SOAP на веб-сервере и обеспечите стабильную работу вашей интеграционной шины.