При работе с Распределенными информационными базами (РИБ) в клиент-серверном режиме «1С:Предприятия» разработчики часто сталкиваются с фундаментальной архитектурной особенностью: все операции по чтению и записи файлов в штатных механизмах обмена Библиотеки стандартных подсистем (БСП) выполняются строго на стороне сервера. Это означает, что если в настройках синхронизации указать путь C:\Exchange, система будет искать эту папку на физическом сервере, где установлен сервер приложений «1С», а не на локальном компьютере пользователя.
В условиях жесткой корпоративной политики безопасности, когда создание общих сетевых ресурсов (расшаренных папок) между сервером и локальными рабочими станциями запрещено, а также закрыт доступ по протоколам FTP, SFTP и заблокированы облачные хранилища, стандартный файловый обмен становится невозможным. Рассмотрим подробнее, как решить эту задачу с помощью программных механизмов платформы «1С:Предприятие 8.3», перенаправив потоки данных напрямую между клиентом и сервером через оперативную память и временные хранилища.
Выясним причину, почему стандартный диалог выбора папки не решает проблему в клиент-серверной архитектуре. В типовой конфигурации «1С:Бухгалтерия 3.0» (и других решениях на базе БСП) код выполнения обмена выполняется в фоновом задании на сервере. Попытка обратиться к файловой системе локального ПК из серверного контекста вызывает ошибку доступа, так как сервер «1С» физически «не видит» диски клиентской машины. Если же оставить путь пустым, система выдаст ошибку о незаполненных настройках транспорта.
Для обхода этого ограничения мы можем использовать клиент-серверный мост передачи файлов, встроенный в платформу «1С». Разберем по шагам несколько эффективных способов реализации этой задачи.
Проанализируем самый надежный программный способ. Мы можем создать внешнюю обработку или встроить в конфигурацию механизм, который будет выступать посредником. Он будет забирать файл обмена, сформированный на сервере, передавать его на клиент через временное хранилище и предлагать пользователю сохранить его на локальный диск. При загрузке процесс будет происходить в обратном порядке.
Рассмотрим пошагово алгоритм выгрузки файла (экспорта из центральной базы):
ПоместитьВоВременноеХранилище().ПолучитьФайл() или асинхронного аналога НачатьПолучениеФайлаССервера().Посмотрим на пример реализации кода для выгрузки файла на стороне клиента и сервера:
// КЛИЕНТСКИЙ КОНТЕКСТ
&НаКлиенте
Процедура ВыгрузитьФайлОбменаНаЛокальныйКомпьютер()
// Получаем адрес временного хранилища с файлом, сформированным на сервере
АдресХранилища = СформироватьФайлОбменаНаСервере();
Если ЗначениеЗаполнено(АдресХранилища) Тогда
// Задаем параметры сохранения файла на локальном ПК пользователя
ИмяФайлаПриемника = "Message_ЦБ_ПБ.xml";
ПараметрыПолучения = Новый ПараметрыПолученияФайловОбъединение();
// Запускаем интерактивное скачивание файла на локальный диск
НачатьПолучениеФайлаССервера(Новый ОписаниеОповещения("ПослеПолученияФайла", ЭтотОбъект), АдресХранилища, ИмяФайлаПриемника);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеПолученияФайла(Результат, ДополнительныеПараметры) Экспорт
ПоказатьПредупреждение(, "Файл обмена успешно сохранен на вашем локальном компьютере!");
КонецПроцедуры
Теперь рассмотрим серверную часть, которая отвечает за генерацию сообщения обмена и его упаковку во временное хранилище:
// СЕРВЕРНЫЙ КОНТЕКСТ
&НаСервере
Функция СформироватьФайлОбменаНаСервере()
// Получаем уникальное имя временного файла на диске сервера
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
// Здесь вызывается штатный механизм выгрузки БСП в файл
// Для примера запишем тестовую XML-структуру, имитирующую обмен
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяВременногоФайла, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("Message");
// Логика выгрузки узла РИБ...
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
// Читаем созданный файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
// Помещаем во временное хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
// Удаляем временный файл с диска сервера, так как он больше не нужен
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
// Обработка исключения, если файл занят процессом
КонецПопытки;
Возврат АдресХранилища;
КонецФункции
Аналогичным образом реализуем обратный процесс — загрузку файла (импорт в центральную базу с локального компьютера пользователя):
ПоместитьФайлНаСервер().Посмотрим на пример реализации загрузки файла:
// КЛИЕНТСКИЙ КОНТЕКСТ
&НаКлиенте
Процедура ЗагрузитьФайлОбменаСЛокальногоКомпьютера()
// Настройка диалога выбора файла на локальном клиенте
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Файлы обмена (*.xml, *.zip)|*.xml;*.zip";
Диалог.Заголовок = "Выберите файл сообщения обмена для загрузки";
Если Диалог.Выбрать() Тогда
ВыбранныйПуть = Диалог.ПолноеИмяФайла;
// Описание обработчика завершения помещения файла на сервер
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайлаНаСервер", ЭтотОбъект, ВыбранныйПуть);
НачатьПомещениеФайлаНаСервер(Оповещение,,, ВыбранныйПуть, УникальныйИдентификатор);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайлаНаСервер(Результат, АдресХранилища, ВыбранныйПуть, ДополнительныеПараметры) Экспорт
Если Результат Тогда
// Файл успешно загружен в хранилище, запускаем его обработку на сервере
РезультатЧтения = ПрочитатьФайлОбменаНаСервере(АдресХранилища);
Если РезультатЧтения Тогда
ПоказатьПредупреждение(, "Файл обмена успешно прочитан и загружен в базу!");
Иначе
ПоказатьПредупреждение(, "Ошибка при обработке файла обмена на сервере.");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Серверная процедура извлекает переданный файл из временного хранилища и передает его механизму чтения РИБ:
// СЕРВЕРНЫЙ КОНТЕКСТ
&НаСервере
Функция ПрочитатьФайлОбменаНаСервере(Знач АдресХранилища)
// Извлекаем двоичные данные из хранилища
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ДвоичныеДанныеФайла = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
// Сохраняем во временный каталог на сервере для последующего чтения
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
Успешно = Истина;
Попытка
// Инициализируем чтение XML и запускаем стандартный обмен БСП
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяВременногоФайла);
// Здесь размещается вызов процедур БСП для загрузки данных в РИБ
// Например: ОбменДаннымиСервер.ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(...)
ЧтениеXML.Закрыть();
Исключение
Успешно = Ложь;
ЗаписатьЛогСобытий("Ошибка обмена: " + ОписаниеОшибки());
КонецПопытки;
// Очищаем временный файл на сервере
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
КонецПопытки;
Возврат Успешно;
Функция
Если мы хотим интегрировать описанный выше механизм непосредственно в стандартный интерфейс синхронизации данных БСП (чтобы пользователям не приходилось запускать отдельную обработку), лучшим решением будет использование расширения конфигурации. Это позволит сохранить типовую конфигурацию «1С:Бухгалтерия» на поддержке без изменений.
Разберем алгоритм перехвата вызовов через расширение:
ОбменДаннымиСервер или формы интерактивного обмена данными).&Вместо или &После перехватываем процедуры записи и чтения файлов обмена.Проанализируем альтернативный штатный вариант, который не требует программирования и изменения конфигурации, но часто разрешен службами безопасности. Если сетевые папки закрыты, но в компании функционирует внутренний почтовый сервер (например, MS Exchange), мы можем настроить обмен через почтовые сообщения.
Рассмотрим, как настроить этот транспорт по шагам:
Этот способ полностью решает проблему «клиент-серверного барьера», так как почтовый клиент встроен в платформу «1С» и все почтовые отправления сервер приложений выполняет самостоятельно, не требуя локального вмешательства пользователя.
Выясним наиболее современный и технологичный подход к организации распределенных систем. Если архитектура сети позволяет опубликовать базу данных на веб-сервере (IIS или Apache), мы можем полностью отказаться от обмена через файлы.
Синхронизация через веб-сервисы работает по следующему принципу:
Этот вариант является приоритетным для высоконагруженных систем, так как исключает человеческий фактор (необходимость ручного копирования файлов) и обеспечивает максимальную безопасность передачи данных по защищенному протоколу HTTPS.