Как правильно организовать запись и сохранение файла в веб-клиенте 1С

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

При переходе с тонкого клиента на веб-клиент разработчики часто сталкиваются с ошибкой "Метод объекта не обнаружен (Записать)" или проблемами при попытке использовать временные файлы. Это происходит из-за того, что архитектура веб-клиента накладывает жесткие ограничения на доступ к локальной файловой системе пользователя из соображений безопасности браузеров. В этой статье мы подробно разберем, почему привычные методы не работают в браузере и как правильно организовать работу с файлами, чтобы она была стабильной и удобной для пользователя.

Анализируем причину ошибки: почему не работает метод Записать?

Рассмотрим ситуацию: у нас есть объект типа ДвоичныеДанные, и мы пытаемся вызвать метод Записать() на стороне клиента. В тонком клиенте это работает без проблем, так как приложение имеет прямой доступ к файловой системе ОС. Однако, если мы заглянем в синтакс-помощник, то увидим, что в разделе "Доступность" для этого метода отсутствует "Веб-клиент".

Проанализируем основные ограничения веб-клиента:

  1. Отсутствие прямого доступа к путям: Веб-клиент не может просто создать файл по пути "C:\Temp\file.docx". Браузер работает в изолированной среде ("песочнице").
  2. Недоступность ПолучитьИмяВременногоФайла: Этот метод также не предназначен для работы в веб-клиенте, так как платформа не может гарантировать создание файла в системных временных папках через браузер.
  3. Синхронность vs Асинхронность: Веб-клиент требует асинхронного взаимодействия при работе с внешними ресурсами, чтобы не блокировать интерфейс браузера.

Решение 1: Использование асинхронных методов с расширением работы с файлами

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

Рассмотрим пример кода, который проверяет наличие расширения и пытается записать данные:


&НаКлиенте
Процедура СохранитьФайлСРасширением(ДанныеФайла, ПутьСохранения)
    #Если ВебКлиент Тогда
        ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПодключенияРасширения", ЭтотОбъект, ДанныеФайла);
        НачатьПодключениеРасширенияРаботыСФайлами(ОписаниеОповещения);
    #КонецЕсли
КонецПроцедуры

&НаКлиенте
Процедура ПослеПодключенияРасширения(Подключено, ДополнительныеПараметры) Экспорт
    Если Подключено Тогда
        // Используем асинхронную запись
        Данные = ДополнительныеПараметры;
        ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗаписиФайла", ЭтотОбъект);
        Данные.НачатьЗапись(ОписаниеОповещения, "C:\MyFiles\document.docx");
    Иначе
        Сообщить("Для записи файла необходимо установить расширение браузера.");
        НачатьУстановкуРасширенияРаботыСФайлами();
    КонецЕсли;
КонецПроцедуры

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

Решение 2: Интерактивное сохранение через НачатьПолучениеФайлаССервера

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

Разберем алгоритм действий по шагам:

  1. Сформируем макет или документ на сервере.
  2. Поместим его во ВременноеХранилище и получим адрес.
  3. Передадим этот адрес на клиент.
  4. Вызовем метод НачатьПолучениеФайлаССервера().

Посмотрим на пример реализации:


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

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

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

Современный подход: Использование Асинхрон (Async/Await) в новых версиях платформы

Если вы работаете на платформе версии 8.3.18 и выше, мы рекомендуем отказаться от сложных ОписаниеОповещения в пользу асинхронных функций. Это сделает ваш код линейным и читаемым. Проанализируем, как изменится код для получения файла:


&НаКлиенте
Асинхрон Процедура СохранитьФайлСовременно(ИмяМакета)
    РезультатСервер = Ждать ПодготовитьФайлНаСервереАсинхрон(ИмяМакета);
    
    // Вместо НачатьПолучение... используем ПолучитьФайлССервераАсинхрон
    Ждать ПолучитьФайлССервераАсинхрон(РезультатСервер.Адрес, РезультатСервер.ИмяФайла);
КонецПроцедуры

Использование ключевых слов Асинхрон и Ждать значительно упрощает разработку под веб-клиент, устраняя необходимость плодить множество мелких процедур для обратных вызовов.

Особенности открытия файлов Word в веб-клиенте

Часто задача звучит не просто "записать", а "открыть файл для редактирования". В тонком клиенте мы используем ЗапуститьПриложение. В веб-клиенте это невозможно сделать напрямую без расширения.

Рассмотрим альтернативы:

Таким образом, для работы в веб-клиенте мы должны полностью сменить парадигму с "прямой записи на диск" на "передачу файла через хранилище и скачивание средствами браузера". Это обеспечит кроссбраузерность и избавит от ошибок, связанных с правами доступа и отсутствием методов в веб-клиенте.

← На главную