При интеграции различных конфигураций 1С часто возникает задача передать сформированный отчет или печатную форму напрямую в другую информационную базу. Табличный документ (ТабличныйДокумент) содержит сложное оформление, ячейки, расшифровки и графические элементы, поэтому важно передать его без потери структуры и с минимальной нагрузкой на каналы связи и дисковую подсистему.
Разберем основные практические способы решения этой задачи, выясним их преимущества и особенности реализации на платформе 1С:Предприятие 8.3.
Проанализируем наиболее быстрый и экономичный способ. Формат MXL является внутренним бинарным контейнером 1С, который штатно использует сжатие. Он полностью сохраняет все оформление документа, шрифты, ширину колонок и группировки. Начиная с версии платформы 8.3.9, нет необходимости сохранять файл на жесткий диск во временный каталог через ПолучитьИмяВременногоФайла() — всю операцию можно выполнить прямо в оперативной памяти с помощью объекта ПотокВПамяти.
Рассмотрим по шагам отправку табличного документа на стороне базы-источника. Нам потребуется записать табличный документ в поток, извлечь двоичные данные и поместить их в тело HTTP-запроса:
// База-отправитель: формируем и отправляем ТабличныйДокумент
ПотокПамяти = Новый ПотокВПамяти();
ТабДок.Записать(ПотокПамяти, ТипФайлаТабличногоДокумента.MXL);
ДвоичныеДанныеДокумента = ПотокПамяти.ЗакрытьИПолучитьДвоичныеДанные();
Соединение = Новый HTTPСоединение("server.domain", 80, "Логин", "Пароль");
Запрос = Новый HTTPЗапрос("/api/v1/mxl");
Запрос.Заголовки.Вставить("Content-Type", "application/octet-stream");
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеДокумента);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Теперь посмотрим на реализацию метода HTTP-сервиса на стороне базы-приемника. Здесь нам нужно извлечь двоичные данные из тела входящего запроса, открыть поток чтения и загрузить данные обратно в ТабличныйДокумент:
// База-получатель: метод HTTP-сервиса
Функция ПринятьТабличныйДокумент(Запрос)
ДвоичныеДанныеТела = Запрос.ПолучитьТелоКакДвоичныеДанные();
ПотокПамяти = Новый ПотокВПамяти(ДвоичныеДанныеТела);
ПринятыйТабДок = Новый ТабличныйДокумент();
ПринятыйТабДок.Прочитать(ПотокПамяти);
ПотокПамяти.Закрыть();
// ПринятыйТабДок готов к использованию (сохранению, показу или печати)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("Успешно получен", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Этот способ оптимален тем, что не выполняет лишних операций кодирования и не нагружает диск операциями ввода-вывода.
Рассмотрим ситуацию, когда табличный документ требуется передать не как отдельный файл, а вместе с сопутствующими метаданными (например, номер документа, дата, тип печатной формы, комментарий). В таком случае двоичные данные табличного документа кодируются в строку формата Base64 и помещаются в структуру JSON.
Посмотрим на пример упаковки документа в JSON на стороне клиента:
// Получаем двоичные данные MXL через поток в памяти
ПотокПамяти = Новый ПотокВПамяти();
ТабДок.Записать(ПотокПамяти, ТипФайлаТабличногоДокумента.MXL);
ДвоичныеДанныеMXL = ПотокПамяти.ЗакрытьИПолучитьДвоичныеДанные();
// Преобразуем в строку Base64
СтрокаBase64 = Base64Строка(ДвоичныеДанныеMXL);
// Формируем пакет данных JSON
Пакет = Новый Структура();
Пакет.Вставить("ИмяОтчета", "ПрайсЛист");
Пакет.Вставить("ДатаФормирования", ТекущаяДатаСессии());
Пакет.Вставить("ДанныеФайла", СтрокаBase64);
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Пакет);
СтрокаJSON = ЗаписьJSON.Закрыть();
// Отправка запроса
Запрос = Новый HTTPЗапрос("/api/v1/report");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(СтрокаJSON);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
На стороне приемника разберем шаги десериализации JSON и восстановления документа:
Функция ОбработатьПакетJSON(Запрос)
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку();
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Пакет = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Извлекаем двоичные данные из строки Base64
ДвоичныеДанныеMXL = Base64Значение(Пакет.ДанныеФайла);
ПотокПамяти = Новый ПотокВПамяти(ДвоичныеДанныеMXL);
ПринятыйТабДок = Новый ТабличныйДокумент();
ПринятыйТабДок.Прочитать(ПотокПамяти);
ПотокПамяти.Закрыть();
Возврат Новый HTTPСервисОтвет(200);
КонецФункции
Важный момент: Кодирование в Base64 увеличивает объем передаваемых полезных данных примерно на 33%. Если передается только сам документ без метаданных, предпочтительнее использовать Способ 1.
Выясним, как работает сериализация объекта через СериализаторXDTO. Платформа 1С умеет сериализовать объект ТабличныйДокумент в XML и обратно без промежуточного сохранения в файл MXL.
Посмотрим на пример выгрузки табличного документа в XML-строку:
// Сериализация документа в XML
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТабДок);
СтрокаXML = ЗаписьXML.Закрыть();
// Отправка через HTTPЗапрос
Запрос = Новый HTTPЗапрос("/api/v1/xdto");
Запрос.Заголовки.Вставить("Content-Type", "application/xml; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(СтрокаXML);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
На стороне получателя достаточно прочитать XML обратно в объект ТабличныйДокумент:
Функция ПринятьXDTO(Запрос)
СтрокаXML = Запрос.ПолучитьТелоКакСтроку();
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(СтрокаXML);
ПринятыйТабДок = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
Возврат Новый HTTPСервисОтвет(200);
КонецФункции
Ограничение метода: XML является текстовым форматом и подробно описывает каждую ячейку, строку и границу. Для объемных отчетов (тысячи строк) XML-представление может занимать в десятки раз больше места, чем сжатый MXL, что вызывает сильный расход оперативной памяти и задержки при сериализации.
При передаче табличных документов между серверами следует учитывать технические особенности инфраструктуры:
413 Payload Too Large. Необходимо заранее скорректировать директивы (например, client_max_body_size в Nginx или maxAllowedContentLength в IIS).ТипФайлаТабличногоДокумента.PDF и передавать готовый PDF-файл.