Почему не работает загрузка из Excel в 1С через веб-клиент и как это исправить?

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

Часто разработчики и пользователи сталкиваются с ситуацией, когда функционал, прекрасно работающий в обычном режиме или при подключении по RDP, перестает функционировать при переходе на веб-клиент или тонкий клиент, подключенный к опубликованной на веб-сервере базе. Типичный пример — загрузка данных из файла Excel, которая внезапно начинает выдавать ошибку: "Ошибка при вызове метода контекста (Прочитать)" с пояснением "Ошибка при выполнении файловой операции". Если вам нужен быстрый старт для решения этой задачи, можно использовать готовый шаблон простой обработки загрузки из excel, но давайте подробно разберемся, почему это происходит и как правильно организовать работу с файлами в клиент-серверной архитектуре самостоятельно.

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


// Этот код выполняется на сервере
ТаблДок = Новый ТабличныйДокумент;
ТаблДок.Прочитать(ИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст);

Когда вы работаете локально, переменная ИмяФайла содержит путь, например, "C:\Temp\data.xlsx", и сервер 1С имеет доступ к этому пути. Но что происходит, когда база опубликована в облаке или на вашем веб-сервере? Давайте выясним причину.

Причина ошибки: разделение контекста выполнения "Клиент" и "Сервер"

Ключ к пониманию проблемы лежит в архитектуре работы 1С в веб-режиме. Весь код в управляемых формах выполняется в двух разных местах (контекстах):

  1. На клиенте (&НаКлиенте): Этот код выполняется на компьютере пользователя. Он отвечает за интерфейс: открытие окон, обработку нажатий кнопок, показ сообщений и, что важно, выбор файлов с локального диска.
  2. На сервере (&НаСервере): Этот код выполняется на машине, где расположен сервер 1С (в случае автора темы — на сервере хостинга e-office24.ru). Он отвечает за всю работу с базой данных: чтение, запись объектов, проведение документов и выполнение сложных расчетов.

Когда пользователь выбирает файл на своем компьютере, путь к этому файлу ("C:\Temp\data.xlsx") существует только на клиенте. Сервер, который физически находится в другом месте, ничего не знает о диске "C:" вашего компьютера. Попытка выполнить на сервере команду ТаблДок.Прочитать("C:\Temp\data.xlsx") обречена на провал — сервер пытается найти этот путь у себя в файловой системе, не находит его и справедливо выдает ошибку "Ошибка при выполнении файловой операции". Именно поэтому любой импорт данных (доступные форматы: *.xls, *. xlsx, *.csv и др.), написанный без учета этой особенности, перестанет работать в веб-клиенте.

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

Правильное решение: передача файла через временное хранилище

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

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

  1. (На клиенте) Инициируем диалог выбора файла, чтобы пользователь указал нужный документ Excel.
  2. (На клиенте) Получив путь к файлу, не передаем его на сервер. Вместо этого мы помещаем сам файл (его двоичные данные) во временное хранилище. Платформа сама позаботится о его передаче на сервер.
  3. (На клиенте) В результате помещения файла мы получаем уникальный адрес этого файла во временном хранилище.
  4. (На клиенте) Вызываем серверную процедуру и передаем в нее не путь к файлу, а этот самый адрес из временного хранилища.
  5. (На сервере) В серверной процедуре, используя полученный адрес, извлекаем двоичные данные файла из хранилища.
  6. (На сервере) Сохраняем эти двоичные данные во временный файл уже на стороне сервера.
  7. (На сервере) Выполняем команду ТаблДок.Прочитать(), указывая путь к этому новому временному файлу на сервере.
  8. (На сервере) После завершения обработки удаляем временный файл на сервере.

Такой подход универсален и будет работать в любом режиме: в толстом, тонком и веб-клиенте. Кстати, именно такой метод передачи данных используется, если вам нужна Из Excel в 1С "одним нажатием" универсальная загрузка, которая работает даже если на сервере не установлен MS Excel.

Пример реализации кода

Давайте посмотрим, как это выглядит на практике. Предположим, на форме есть команда ЗагрузитьИзФайла.

Шаг 1. Создаем клиентскую процедуру-обработчик команды

Эта процедура будет отвечать за выбор файла и его помещение во временное хранилище.


&НаКлиенте
Процедура ЗагрузитьИзФайла(Команда)
    
    // Открываем диалог выбора файла
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Заголовок = "Выберите файл для загрузки";
    Диалог.Фильтр = "Лист Excel (*.xls, *.xlsx)|*.xls;*.xlsx";
    Диалог.МножественныйВыбор = Ложь;
    
    Если Диалог.Выбрать() Тогда
        ВыбранныйФайл = Диалог.ПолноеИмяФайла;
        
        // Помещаем файл во временное хранилище и получаем его адрес
        АдресВоВременномХранилище = "";
        ПоместитьФайл(АдресВоВременномХранилище, ВыбранныйФайл, , Ложь);
        
        // Если адрес получен, вызываем серверную процедуру для обработки
        Если ЗначениеЗаполнено(АдресВоВременномХранилище) Тогда
            ПрочитатьФайлНаСервере(АдресВоВременномХранилище);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Создаем серверную процедуру для чтения файла

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


&НаСервере
Процедура ПрочитатьФайлНаСервере(АдресВоВременномХранилище)
    
    // Получаем двоичные данные файла из временного хранилища
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВоВременномХранилище);
    
    // Определяем имя для временного файла на сервере
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    
    // Записываем двоичные данные в этот временный файл
    ДвоичныеДанные.Записать(ИмяВременногоФайла);
    
    // Теперь можем безопасно прочитать файл на сервере
    ТабличныйДокумент = Новый ТабличныйДокумент;
    Попытка
        ТабличныйДокумент.Прочитать(ИмяВременногоФайла);
        // ... дальнейшая обработка данных из ТабличныйДокумент ...
        Сообщить("Файл успешно прочитан!");
    Исключение
        ОписаниеОшибки = ОписаниеОшибки();
        Сообщить("Не удалось прочитать файл. " + ОписаниеОшибки);
    КонецПопытки;
    
    // Обязательно удаляем за собой временный файл на сервере
    УдалитьФайлы(ИмяВременногоФайла);
    
КонецПроцедуры

Улучшение для больших файлов: асинхронный режим

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

Вот как будет выглядеть клиентский код с использованием асинхронного подхода:


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

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

Серверная процедура ПрочитатьФайлНаСервере() при этом остается без изменений. Такой подход обеспечивает лучший пользовательский опыт, так как интерфейс не блокируется во время передачи данных.

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

← На главную