Как редактировать и сохранять файлы обратно на сервер в веб-клиенте 1С?

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

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

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

Почему возникают ошибки файловой системы в веб-клиенте

Выясним причину, почему код, работающий в тонком клиенте, не исполняется в браузере:

  1. Ограничения песочницы браузера (Sandbox): Веб-клиент не имеет прямого доступа к локальным папкам и файлам на компьютере пользователя без специального разрешения.
  2. Использование адресов временного хранилища: Навигационная ссылка вида e1cib/tempstorage/... является лишь внутренним адресом данных в сеансе 1С, а не реальным путем файловой системы Windows или Linux.
  3. Необходимость специального расширения: Для выполнения операций с файлами на диске (получение каталогов, создание локальных файлов, запуск сторонних программ) требуется предварительное подключение расширения работы с файлами.

Шаг 1. Подключение расширения работы с файлами

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

Рассмотрим пример проверки и подключения расширения:


#Если ВебКлиент Тогда
    Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
        УстановитьРасширениеРаботыСФайлами();
        ПодключитьРасширениеРаботыСФайлами();
    КонецЕсли;    
#КонецЕсли

Шаг 2. Получение файла с сервера и запуск для редактирования

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

Сначала на сервере получаем двоичные данные файла и помещаем их во временное хранилище, а затем на клиенте вызываем метод ПолучитьФайлы():


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

&НаКлиенте
Процедура КнопкаРедактировать(Команда)
    
    #Если ВебКлиент Тогда
        Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
            УстановитьРасширениеРаботыСФайлами();
            ПодключитьРасширениеРаботыСФайлами();
        КонецЕсли;    
    #КонецЕсли

    ЛокальныйПутьКФайлу = ОбщиеФункцииКлиент.ВернутьПутьКФайлу(Объект.Номер, Объект.НазваниеИзмененныйДоговор);
    
    Если ОбщиеФункцииКлиент.КаталогСуществует(ЛокальныйПутьКФайлу) Тогда
        Попытка
            ЗапуститьПриложение(ЛокальныйПутьКФайлу);
        Исключение
            Сообщить(ОписаниеОшибки());        
        КонецПопытки;        
    Иначе
        Попытка
            ВременныйАдрес = ВернутьАдресХранилища(); 

            ПолучаемыйФайл = Новый ОписаниеПередаваемогоФайла(ЛокальныйПутьКФайлу, ВременныйАдрес);
            ПолучаемыеФайлы = Новый Массив;
            ПолучаемыеФайлы.Добавить(ПолучаемыйФайл);
            
            ПолученныеФайлы = Новый Массив;                
            
            Если ПолучитьФайлы(ПолучаемыеФайлы, ПолученныеФайлы, ЛокальныйПутьКФайлу, Ложь) Тогда
                ЗапуститьПриложение(ЛокальныйПутьКФайлу);
                Объект.ДоговорРедактируется = Истина;
            КонецЕсли;
        Исключение
            Сообщить(ОписаниеОшибки());       
        КонецПопытки;
    КонецЕсли;      
    
КонецПроцедуры

Шаг 3. Сохранение измененного файла обратно в базу 1С

После того как пользователь отредактировал и сохранил документ на локальном диске, нам необходимо перенести обновленную версию обратно в базу данных. Для этого используем метод ПоместитьФайлы(), который передает файл с клиента во временное хранилище на сервере.

Рассмотрим реализацию клиентской процедуры сохранения и серверного метода записи данных:


&НаКлиенте
Процедура КнопкаСохранить(Команда)
    
    #Если ВебКлиент Тогда
        Если НЕ ПодключитьРасширениеРаботыСФайлами() Тогда
            УстановитьРасширениеРаботыСФайлами();
            ПодключитьРасширениеРаботыСФайлами();                    
        КонецЕсли;    
    #КонецЕсли
         
    ЛокальныйПутьКФайлу = ОбщиеФункцииКлиент.ВернутьПутьКФайлу(Объект.Номер, Объект.НазваниеИзмененныйДоговор);
         
    Попытка
        Если ОбщиеФункцииКлиент.КаталогСуществует(ЛокальныйПутьКФайлу) Тогда
            
            ЗагружаемыйФайл = Новый Файл(ЛокальныйПутьКФайлу);
            
            ПомещаемыеФайлы = Новый Массив;
            ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(ЛокальныйПутьКФайлу));
            ПомещенныеФайлы = Новый Массив;
            
            ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ЭтаФорма.УникальныйИдентификатор);        
            
            СохранитьВерсиюИсполнителя(ПомещенныеФайлы[0].Хранение, ЛокальныйПутьКФайлу, ЗагружаемыйФайл.Размер());
            Объект.ДоговорРедактируется = Ложь;
        Иначе
            Сообщить("Редактируемый файл не найден в каталоге!"); 
        КонецЕсли;
    Исключение
        Сообщить(ОписаниеОшибки()); 
    КонецПопытки;
          
КонецПроцедуры

&НаСервере
Процедура СохранитьВерсиюИсполнителя(вхВременныйАдрес, вхИмяФайла, вхРазмерФайла)
    
    Если вхВременныйАдрес <> Неопределено Тогда
        
        // Получаем двоичные данные из временного хранилища
        ДвоичныеДанные = ПолучитьИзВременногоХранилища(вхВременныйАдрес);
        
        НайденныйФайл = РегистрыСведений.ВременноеХранилищеФайлов.СоздатьНаборЗаписей();
        НайденныйФайл.Отбор.ВладелецФайла.Установить(Объект.Ссылка);
        НайденныйФайл.Прочитать();
        
        ВремяПериода = ТекущаяДата();
        
        Если НайденныйФайл.Количество() = 0 Тогда 
            
            НовоеИмяФайла = "(V1) " + ОбщиеФункцииСервер.ВернутьИмяФайла(вхИмяФайла);
            ИмяИсполнителя = ОбщиеФункцииСервер.ТекущийПользователь();
            
            МенеджерЗаписи = РегистрыСведений.ВременноеХранилищеФайлов.СоздатьМенеджерЗаписи();
            МенеджерЗаписи.Период = ВремяПериода;               
            МенеджерЗаписи.РазмерФайла = Окр((вхРазмерФайла / 1024) / 1024, 3);
            МенеджерЗаписи.ВладелецФайла = Объект.Ссылка;
            МенеджерЗаписи.ИмяФайла = НовоеИмяФайла; 
            МенеджерЗаписи.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
            МенеджерЗаписи.ТипФайла = ОбщиеФункцииСервер.ТипИнформации("Основная");
            МенеджерЗаписи.АвторФайла = ИмяИсполнителя;
            МенеджерЗаписи.Записать();
            
            Объект.НазваниеДоговораИсполнителя = НовоеИмяФайла;                
            Объект.АвторДоговораИсполнителя = ИмяИсполнителя;
            
        Иначе 
            
            Для Каждого Запись Из НайденныйФайл Цикл 
                Запись.Период = ВремяПериода;
                Запись.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
                Запись.РазмерФайла = Окр((вхРазмерФайла / 1024) / 1024, 3);
            КонецЦикла;
            
            НайденныйФайл.Записать();                
            
        КонецЕсли;
        
        Объект.ДатаДоговораИсполнителя = ВремяПериода;
        Объект.РазмерДоговораИсполнителя = Окр((вхРазмерФайла / 1024) / 1024, 3);
        
    КонецЕсли;
    
КонецПроцедуры

Особенности работы в современных версиях платформы (8.3.18+)

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

  1. ПодключитьРасширениеРаботыСФайламиАсинх()
  2. ПолучитьФайлыАсинх() или ПолучитьФайлССервераАсинх()
  3. ПоместитьФайлыАсинх() или ПоместитьФайлНаСерверАсинх()
  4. ЗапуститьПриложениеАсинх()

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

← На главную