Как передать значение или файл с клиента на сервер в 1С:Разбор методов и лучших практик

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В разработке на платформе «1С:Предприятие 8.3» одним из фундаментальных правил является четкое разделение контекста исполнения кода на клиентский и серверный. Клиент отвечает за взаимодействие с пользователем и отображение интерфейса, в то время как сервер выполняет тяжелые вычисления, работу с базой данных и бизнес-логику. Рано или поздно перед каждым разработчиком встает задача: как передать данные, доступные на клиенте, в серверную процедуру?

Особую сложность этот вопрос вызывает тогда, когда речь заходит о файлах и путях к ним. В этой статье мы подробно разберем, как правильно передавать простые значения, почему прямая передача пути к файлу является ошибкой, и как организовать корректный перенос файлов с клиентского компьютера на сервер с использованием современных механизмов платформы.

Понимание клиент-серверной архитектуры 1С

Прежде чем перейти к написанию кода, давайте проанализируем, почему нельзя просто так взять и использовать клиентские данные на сервере. Клиентское приложение (тонкий клиент, веб-клиент) и сервер приложений 1С — это физически разные процессы, которые могут выполняться на абсолютно разных компьютерах, находящихся в разных точках мира.

Для обмена данными между ними платформа выполняет операцию сериализации — перевода объектов 1С в поток байтов (обычно XML или JSON) для передачи по сети, и последующей десериализации на принимающей стороне. Из этого вытекает первое золотое правило разработки:

Между клиентом и сервером можно передавать только те типы данных, которые поддерживают сериализацию.

К таким типам относятся:

  1. Простые типы данных: Число, Строка, Булево, Дата, Неопределено.
  2. Базовые коллекции: Массив, Структура, Соответствие, а также ТаблицаЗначений (последняя — с ограничениями: ее колонки должны содержать только сериализуемые типы).
  3. Ссылки на объекты базы данных: Ссылки на справочники, документы, перечисления и т.д.

Такие объекты, как ДиалогВыбораФайла, COM-объекты, драйверы оборудования или открытые сессии внешних соединений, существуют исключительно в памяти клиента и не могут быть переданы на сервер.

Способ 1: Передача простых данных через параметры процедур

Рассмотрим простейшую ситуацию: на клиенте у нас есть текстовая строка (например, артикул товара или поисковый запрос), и нам нужно обработать ее на сервере. Самый очевидный и правильный способ — передать это значение в качестве параметра при вызове серверного метода.

Давайте посмотрим на практический пример:


&НаКлиенте
Процедура ВыполнитьПоискНаКлиенте()
    СтрокаПоиска = "Шоколад Аленка"; // Значение получено на клиенте
    
    // Передаем значение в качестве параметра серверной функции
    НайденныеТовары = НайтиТоварыНаСервере(СтрокаПоиска);
    
    // Обрабатываем результат на клиенте
    Если НайденныеТовары.Количество() > 0 Тогда
        ПоказатьПредупреждение(, "Товары успешно найдены!");
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция НайтиТоварыНаСервере(Знач ПоисковыйЗапрос)
    // Серверный контекст. Здесь доступна база данных.
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |	Номенклатура.Наименование ПОДОБНО &Наименование";
    
    Запрос.УстановитьПараметр("Наименование", "%" + ПоисковыйЗапрос + "%");
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции

В данном примере мы использовали директиву компиляции &НаСервереБезКонтекста. Это наиболее эффективный метод вызова сервера, так как при этом на сервер не передаются данные всей формы (ее реквизиты), что существенно экономит сетевой трафик и ускоряет работу системы.

Ловушка «Пути к файлу»: почему передача строки-пути не работает

Очень часто начинающие разработчики совершают классическую ошибку. Получив на клиенте путь к файлу (например, "C:\Users\User\Documents\Report.xlsx"), они передают эту строку на сервер в надежде, что серверный код сможет открыть и прочитать этот файл. Давайте выясним, почему эта схема обречена на провал в реальной эксплуатации.

Если база данных работает в файловом режиме на одном и том же компьютере разработчика, этот код сработает. Но как только конфигурация будет развернута в полноценном клиент-серверном варианте, произойдет следующее:

  1. Сервер 1С физически находится на другом сервере (в серверной стойке или облаке).
  2. Серверный процесс выполняется от имени специальной системной учетной записи (например, usr1cv8).
  3. Когда сервер получит строку пути "C:\Users\User\Documents\Report.xlsx", он попытается найти этот файл на своем собственном локальном диске "C:". Разумеется, такого файла там нет, и система вернет ошибку доступа или сообщение о том, что файл не найден.

Исключение из правила: Передача строкового пути имеет смысл только тогда, когда файл лежит в общей сетевой папке (имеет UNC-путь вида \\ServerName\ShareFolder\file.xlsx) и служба сервера 1С имеет полные права операционной системы на чтение и запись в эту сетевую директорию. Во всех остальных случаях необходимо передавать на сервер сам файл, а не путь к нему.

Способ 2: Передача файла через Временное Хранилище

Единственный надежный способ обработать клиентский файл на сервере — это переслать его содержимое в виде двоичных данных. Для этого в платформе 1С предусмотрен специальный механизм — Временное хранилище.

Временное хранилище представляет собой выделенную область памяти на сервере приложений 1С, куда клиент может временно поместить данные и получить уникальный строковый адрес вида e1cib/tempstorage/.... Этот адрес легко передается между клиентом и сервером как обычная строка.

Давайте разберем по шагам классический программный алгоритм передачи файла, когда путь к файлу на клиенте нам уже известен:


&НаКлиенте
Процедура ПередатьФайлНаСервер()
    ПутьКФайлуНаКлиенте = "C:\MyFiles\Data.txt"; // Путь на клиентском ПК
    
    // Шаг 1. Читаем файл в объект ДвоичныеДанные на клиенте
    Попытка
        ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлуНаКлиенте);
    Исключение
        Сообщить("Не удалось прочитать файл на клиенте: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // Шаг 2. Помещаем двоичные данные во временное хранилище.
    // Привязываем адрес к УникальномуИдентификатору формы. 
    // Это гарантирует, что платформа автоматически очистит память при закрытии формы.
    АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, ЭтаФорма.УникальныйИдентификатор);
    
    // Шаг 3. Передаем адрес на сервер для обработки
    ОбработатьФайлНаСервере(АдресВременногоХранилища);
КонецПроцедуры

&НаСервере
Процедура ОбработатьФайлНаСервере(Знач АдресХранилища)
    // Шаг 4. На сервере получаем двоичные данные по адресу
    ДвоичныеДанныеНаСервере = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    Если ДвоичныеДанныеНаСервере = Неопределено Тогда
        ВызватьИсключение "Ошибка получения данных из временного хранилища!";
    КонецЕсли;
    
    // Шаг 5. Создаем временный файл на сервере для последующего анализа
    ИмяВременногоФайлаНаСервере = ПолучитьИмяВременногоФайла("txt");
    ДвоичныеДанныеНаСервере.Записать(ИмяВременногоФайлаНаСервере);
    
    // Шаг 6. Здесь выполняется непосредственное чтение и обработка файла.
    // Например, чтение текстового файла:
    ТекстовыйДокумент = Новый ТекстовыйДокумент;
    ТекстовыйДокумент.Прочитать(ИмяВременногоФайлаНаСервере);
    
    Для НомерСтроки = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
        СтрокаТекста = ТекстовыйДокумент.ПолучитьСтроку(НомерСтроки);
        // Выполняем бизнес-логику...
    КонецЦикла;
    
    // Шаг 7. Обязательно удаляем временный файл на сервере, чтобы не переполнять диск!
    Попытка
        УдалитьФайлы(ИмяВременногоФайлаНаСервере);
    Исключение
        ЗаписьЖурналаРегистрации("ОчисткаВременныхФайлов", УровеньЖурналаРегистрации.Предупреждение,,,
            "Не удалось удалить временный файл: " + ИмяВременногоФайлаНаСервере);
    КонецПопытки;
КонецПроцедуры

Способ 3: Современный интерактивный метод (Платформа 8.3.15+)

В современных конфигурациях 1С, работающих в управляемом режиме (особенно в веб-клиенте), синхронные методы работы с файлами считаются устаревшими и могут вызывать блокировку интерфейса. Платформа предоставляет мощный асинхронный инструмент: метод НачатьПомещениеФайлаНаСервер().

Этот метод работает асинхронно, открывает стандартное окно выбора файлов для пользователя и автоматически отправляет выбранный файл во временное хранилище, возвращая управление в специальную процедуру-оповещение. Давайте разберем этот продвинутый паттерн программирования:


&НаКлиенте
Процедура НачатьЗагрузкуФайла(Команда)
    // Описываем, какую процедуру вызвать после того, как файл будет загружен в облако/сервер
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗагрузкиФайлаНаСервер", ЭтотОбъект);
    
    ПараметрыЗагрузки = Новый ПараметрыПомещенияФайлаНаСервер;
    ПараметрыЗагрузки.Интерактивно = Истина; // Откроет диалог выбора файла
    ПараметрыЗагрузки.Заголовок = "Выберите файл для обработки на сервере";
    
    // Запускаем асинхронный процесс
    НачатьПомещениеФайлаНаСервер(ОписаниеОповещения,,,, ПараметрыЗагрузки, ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗагрузкиФайлаНаСервер(РезультатПомещения, ДополнительныеПараметры) Экспорт
    // Проверяем, успешно ли завершился процесс
    Если РезультатПомещения <> Неопределено И РезультатПомещения.ИмяФайлаПомещено Тогда
        // Адрес временного хранилища находится в свойстве "Адрес"
        АдресХранилища = РезультатПомещения.Адрес;
        ИмяФайла = РезультатПомещения.СсылкаНаФайл.Имя;
        
        Сообщить(СтрШаблон("Файл %1 успешно загружен. Отправляем на сервер...", ИмяФайла));
        
        // Передаем адрес во временном хранилище на сервер для разбора
        РазобратьДанныеНаСервере(АдресХранилища);
    Иначе
        ПоказатьПредупреждение(, "Загрузка файла была отменена пользователем.");
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Процедура РазобратьДанныеНаСервере(Знач АдресХранилища)
    // Извлекаем двоичные данные на сервере без контекста формы
    ДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    // Выполняем обработку...
    // (например, парсинг Excel, чтение XML-данных или загрузка картинок)
КонецПроцедуры

Рекомендации по оптимизации работы с временными хранилищами

Работа с временным хранилищем требует аккуратности, особенно в высоконагруженных системах с сотнями одновременно работающих пользователей. Проанализируем ключевые рекомендации по обеспечению стабильности и производительности:

  1. Привязка к Уникальному Идентификатору формы. При вызове метода ПоместитьВоВременноеХранилище() всегда передавайте вторым параметром ЭтаФорма.УникальныйИдентификатор. Если этого не сделать, данные будут жить в памяти сервера до окончания сеанса пользователя. Если пользователь загрузит десяток тяжелых файлов по 100 МБ, сервер быстро исчерпает доступную оперативную память. Привязка к форме уничтожит эти данные сразу после закрытия окна формы.
  2. Очистка временных файлов ОС. Если на сервере вы записываете двоичные данные во временный файл методом ПолучитьИмяВременногоФайла(), всегда помещайте блок удаления файла в конструкцию Попытка...Исключение. Не удаленные временные файлы операционной системы способны за несколько недель полностью забить дисковое пространство сервера приложений 1С.
  3. Передавайте только то, что нужно. Если вам нужно передать структуру настроек интерфейса с клиента на сервер, не пишите ее в файл. Используйте обычную структуру 1С и передавайте её параметром в вызов &НаСервереБезКонтекста. Платформа сама оптимизирует процесс ее сериализации.

Подводя итог, можно сказать, что передача клиентских значений на сервер — стандартная и ежедневная задача разработчика 1С. Понимание принципов сериализации данных и механизмов работы с временным хранилищем позволит вам писать надежный, быстрый и отказоустойчивый код, который будет корректно работать в любых архитектурных условиях.

← На главную