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

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

При переходе от толстого или тонкого клиента к веб-клиенту многие разработчики сталкиваются с тем, что привычные методы работы с файловой системой перестают работать. Браузер — это изолированная среда ("песочница"), которая ради безопасности не позволяет сайтам (а веб-клиент для браузера — это сайт) свободно читать и писать файлы на диск пользователя C:\ или D:\.

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

Проблема: Почему не работает старый код?

В классическом тонком клиенте (Desktop) мы привыкли использовать следующий алгоритм:

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

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

Задача 1: Сохранение отчета и прикрепление к объекту

Частая задача: пользователь формирует отчет, нажимает кнопку, и система должна сохранить этот отчет в формате Excel (XLSX) и прикрепить его к справочнику "Файлы" или к документу.

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

Правильное решение: Все действия по генерации и сохранению файла нужно выполнять на стороне сервера. Клиент (браузер) должен лишь отправить команду.

Разберем алгоритм:

  1. На клиенте пользователь нажимает кнопку.
  2. Вызываем серверную процедуру.
  3. На сервере формируем табличный документ.
  4. Сохраняем его во временный поток в памяти (или во временный файл на сервере).
  5. Создаем объект присоединенного файла и записываем в него данные.

Посмотрим на пример кода, как это реализовать, используя потоки в памяти (это быстрее и надежнее, чем создавать мусорные файлы на диске сервера):


// Процедура на Сервере
Процедура ПрикрепитьОтчетКОбъектуНаСервере(СсылкаНаОбъект)
    
    // 1. Формируем отчет
    ТабДок = Новый ТабличныйДокумент;
    // ... здесь код заполнения макета и параметров ...
    
    // 2. Сохраняем в поток в памяти (без создания файла на диске)
    ПотокВПамяти = Новый ПотокВПамяти();
    ТабДок.Записать(ПотокВПамяти, ТипФайлаТабличногоДокумента.XLSX);
    
    // 3. Получаем двоичные данные из потока
    ДвоичныеДанныеФайла = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();
    
    // 4. Помещаем во временное хранилище (если нужно для дальнейшей обработки)
    // или сразу создаем присоединенный файл
    АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
    
    // Пример создания файла (зависит от вашей конфигурации/БСП)
    НовыйФайл = Справочники.Файлы.СоздатьЭлемент();
    НовыйФайл.ВладелецФайла = СсылкаНаОбъект;
    НовыйФайл.Наименование = "Отчет от " + ТекущаяДата() + ".xlsx";
    // ... логика записи данных в регистры или реквизиты хранения файлов ...
    // РаботаСУниверсальнымиМеханизмами.ДобавитьФайл(... АдресВХранилище ...);
    
КонецПроцедуры

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

Задача 2: Отправка файла HTTP-запросом с клиента

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

Чтобы отправить файл с клиента (из браузера), нам нужно сначала передать данные этого файла с сервера на клиент.

Алгоритм действий:

  1. На сервере: Формируем файл (или получаем его из базы), получаем его ДвоичныеДанные.
  2. На сервере: Помещаем двоичные данные во временное хранилище методом ПоместитьВоВременноеХранилище. Получаем навигационную ссылку (Адрес).
  3. На клиенте: Получаем адрес временного хранилища.
  4. На клиенте: Используем средства работы с HTTP для отправки.

Однако здесь нас подстерегает серьезная проблема веб-клиента — CORS (Cross-Origin Resource Sharing).

Важное предупреждение про CORS:

Если вы попытаетесь из веб-клиента (который загружен, например, с домена my-1c-server.ru) отправить AJAX/HTTP запрос на чужой домен (например, api.external-service.com), браузер заблокирует этот запрос, если внешний сервер специально не разрешает такие запросы заголовками Access-Control-Allow-Origin.

Если внешний сервис вам не подконтролен, отправить запрос с веб-клиента, скорее всего, не получится. В таком случае вам придется решать вопрос с администрированием сети и разрешать доступ серверу 1С.

Если же CORS настроен или вы работаете в рамках одного домена, код на клиенте будет выглядеть так:


// Асинхронная процедура на Клиенте
Асинх Процедура ОтправитьФайлСКлиента(АдресФайлаВХранилище)
    
    // Получаем двоичные данные из временного хранилища на клиент
    // В веб-клиенте это может потребовать дополнительных шагов, 
    // но для HTTP соединения часто достаточно передать ДвоичныеДанные
    
    ДанныеФайла = ПолучитьИзВременногоХранилища(АдресФайлаВХранилище); // Внимание: работает не во всех контекстах веб-клиента напрямую с большими объемами
    
    // Создаем соединение
    Соединение = Новый HTTPСоединение("api.example.com", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    Запрос = Новый HTTPЗапрос("/upload");
    Запрос.УстановитьТелоИзДвоичныхДанных(ДанныеФайла);
    
    // Асинхронный вызов, чтобы не блокировать интерфейс браузера
    Попытка
        Ответ = Ждать Соединение.ВызватьHTTPМетодАсинх("POST", Запрос);
        Сообщить("Файл отправлен, код ответа: " + Ответ.КодСостояния);
    Исключение
        Сообщить("Ошибка отправки: " + ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Задача 3: Открытие файла для просмотра

Как в веб-клиенте показать пользователю сформированный Excel или PDF? Привычный ЗапуститьПриложение() здесь работает иначе.

Есть два сценария:

Сценарий А: Без расширения работы с файлами

Если у пользователя не установлено расширение работы с файлами, браузер не может просто так открыть Excel. Он может только скачать файл. Для этого используется метод ПолучитьФайл() или переход по навигационной ссылке.

Сценарий Б: С расширением работы с файлами

Если расширение установлено, браузер получает больше прав и может инициировать запуск локального приложения. Для этого следует использовать современные асинхронные методы.

Используйте ЗапуститьПриложениеАсинх (доступно с версии 8.3.18 как стандарт, ранее через Callback).


&НаКлиенте
Асинх Процедура ОткрытьФайлПоКнопке(Команда)
    
    // Предварительно файл должен быть помещен во временное хранилище на сервере
    Адрес = ПолучитьАдресФайлаНаСервере(); 
    ИмяФайла = "Отчет.xlsx";
    
    Попытка
        // Получаем файл из хранилища и предлагаем открыть
        // Если подключено расширение - 1С попытается открыть его в Excel
        // Если нет - браузер предложит сохранить файл
        Ждать ПолучитьФайлССервераАсинх(Адрес, ИмяФайла, Истина); 
    Исключение
        Сообщить("Не удалось получить файл: " + ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Если вам нужно просто "открыть" файл, который уже лежит где-то локально (что редкость для веб-клиента) или по URL, используйте:


&НаКлиенте
Процедура ОткрытьВнешнююСсылку()
    // Это заставит браузер открыть ссылку в новой вкладке или скачать файл
    ЗапуститьПриложениеАсинх("https://mysite.com/report.pdf");
КонецПроцедуры

Рекомендации по БСП

Если ваша конфигурация построена на базе Библиотеки Стандартных Подсистем (БСП), настоятельно рекомендуем не писать велосипеды для рассылки отчетов.

В БСП есть подсистема "Рассылка отчетов". Она позволяет:

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

Выводы

  1. В веб-клиенте избегайте сохранения файлов на клиенте для промежуточной обработки. Формируйте и обрабатывайте файлы на сервере.
  2. Для передачи данных между сервером и клиентом используйте ВременноеХранилище.
  3. Для HTTP-запросов с клиента помните про ограничения безопасности браузеров (CORS).
  4. Используйте современные асинхронные методы (Ждать, Асинх) вместо устаревших обработчиков оповещения.
  5. По возможности используйте стандартные механизмы БСП для рассылок.
← На главную