Как программно создать каталог и сохранить файл через HTTP-сервис в 1С:Предприятие?

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

Работа с файловой системой в контексте HTTP-сервисов часто преподносит сюрпризы даже опытным разработчикам. Ситуация, когда код идеально работает в обычной внешней обработке, но «тихо» ломается при вызове через веб-сервер, — классическая проблема. В этой статье мы подробно разберем, почему так происходит, и как правильно реализовать создание сетевых каталогов и запись файлов на сервере.

Разберем причину: разница в контекстах выполнения

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

Однако, когда тот же самый код вызывается через HTTP-сервис, ситуация кардинально меняется:

  1. Пользователь службы 1С: Если база клиент-серверная, код выполняется под учетной записью, от которой запущен ragent (обычно это USR1CV8). У этой учетной записи по умолчанию нет прав на сетевые ресурсы.
  2. Контекст веб-сервера: Если используется IIS, в игру вступают права «Пула приложений» (Application Pool Identity). Даже если у пользователя 1С есть права, веб-сервер может блокировать доступ к файловой системе из соображений безопасности.

Проблема "молчаливого" отказа метода СоздатьКаталог

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

Рассмотрим пример кода, который часто приводит к ошибке:


ИмяПапки = "\\Server\Share\NewFolder";
СоздатьКаталог(ИмяПапки); 
// На платформе 8.3.6 здесь не будет ошибки, даже если папка не создалась
Файл = Новый Файл(ИмяПапки);
Если Не Файл.Существует() Тогда
    // Вот здесь мы внезапно обнаруживаем, что каталога нет
КонецЕсли;

Ловушка временного хранилища в HTTP-сервисах

Одной из самых коварных ошибок является попытка использовать ПолучитьИзВременногоХранилища() внутри метода HTTP-сервиса. Рассмотрим ситуацию: автор темы передает адрес временного хранилища и пытается записать данные на диск.

Важно понимать: HTTP-запрос в 1С — это новый сеанс. Временное хранилище живет ровно столько, сколько живет сеанс. Если вы поместили файл в хранилище в одном сеансе (например, в обработке), а пытаетесь достать его в методе POST или GET HTTP-сервиса, вы получите Неопределено. Именно поэтому возникает ошибка «Значение не является значением объектного типа (Записать)».

Чтобы этого избежать, мы должны передавать двоичные данные файла непосредственно в теле HTTP-запроса. Посмотрим, как это реализовать правильно:


// В методе HTTP-сервиса (например, POST)
ДвоичныеДанные = Запрос.ПолучитьТелоКакДвоичныеДанные();
Если ДвоичныеДанные = Неопределено Тогда
    // Обработка ошибки: тело запроса пустое
КонецЕсли;

Работа с сетевыми задержками и UNC-путями

При работе с сетевыми каталогами (пути вида \\Server\Folder) возникает эффект задержки. После команды СоздатьКаталог() операционной системе требуется время (иногда до нескольких сотен миллисекунд), чтобы обновить информацию в сетевом кэше. Если мы проверим Файл.Существует() мгновенно после создания, система может вернуть Ложь.

Рекомендуем использовать небольшую паузу или цикл проверки:


СоздатьКаталог(СетевойПуть);
Для Итерация = 1 По 5 Цикл
    ТестовыйФайл = Новый Файл(СетевойПуть);
    Если ТестовыйФайл.Существует() Тогда
        Прервать;
    КонецЕсли;
    // Небольшая задержка (можно использовать Sleep через COM или просто пустой цикл)
КонецЦикла;

Безопасное копирование: почему КомандаСистемы — плохое решение

В обсуждении предлагалось использовать xcopy через КомандаСистемы(). Мы крайне не рекомендуем этот способ для HTTP-сервисов по следующим причинам:

Вместо этого мы должны использовать встроенные средства 1С, такие как КопироватьФайл() или объекты для работы с двоичными данными.

Итоговый алгоритм реализации надежного создания каталога

Рассмотрим пошагово, как правильно построить процесс приема файла через HTTP-сервис и сохранение его в создаваемый каталог:

  1. Извлекаем данные из запроса: Используем Запрос.ПолучитьТелоКакДвоичныеДанные(). Забудьте про временное хранилище (адреса e1cib/tempstorage/...) в контексте вызова внешних систем.
  2. Формируем путь: Проверяем, что в пути нет запрещенных символов, которые могли прийти в заголовках запроса.
  3. Создаем каталог во временной папке: Если создание сразу в сети вызывает проблемы с правами, сначала создаем папку локально на сервере, используя КаталогВременныхФайлов(). У службы 1С гарантированно есть туда доступ.
  4. Записываем файл: Сохраняем двоичные данные в локальную временную папку.
  5. Переносим в сеть: Используем КопироватьФайл() для перемещения файла из временной папки в целевой сетевой каталог.

Посмотрим на пример надежного кода:


Функция СохранитьФайлИзЗапроса(Запрос)
    
    // 1. Получаем данные
    ДанныеФайла = Запрос.ПолучитьТелоКакДвоичныеДанные();
    ИмяФайла = Запрос.Заголовки.Получить("X-File-Name"); // Передаем имя в заголовке
    
    // 2. Определяем пути
    СетевойКаталог = "\\FileServer\Uploads\" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd");
    
    // 3. Попытка создания каталога с проверкой
    Попытка
        СоздатьКаталог(СетевойКаталог);
    Исключение
        ЗаписьЖурналаРегистрации("ОшибкаФайлов", УровеньЖурналаРегистрации.Ошибка, , , 
            "Не удалось создать каталог: " + ОписаниеОшибки());
        Возврат Новый HTTPСервисОтвет(500);
    КонецПопытки;
    
    // 4. Запись файла
    ПолныйПуть = СетевойКаталог + "\" + ИмяФайла;
    Попытка
        ДанныеФайла.Записать(ПолныйПуть);
    Исключение
        // Здесь мы поймаем ошибку прав доступа ОС
        ЗаписьЖурналаРегистрации("ОшибкаФайлов", УровеньЖурналаРегистрации.Ошибка, , , 
            "Ошибка записи в сетевой каталог: " + ОписаниеОшибки());
        Возврат Новый HTTPСервисОтвет(403); // Forbidden
    КонецПопытки;

    Возврат Новый HTTPСервисОтвет(200);
    
КонецФункции

Как проверить права, если нет доступа к серверу?

Если вы программист и у вас нет админского доступа к серверу, проанализируем ситуацию с помощью простого теста. Напишите временную внешнюю обработку, которая делает СоздатьКаталог(), и запустите её на сервере через консоль заданий (регламентное задание). Если регламентное задание упадет с ошибкой доступа — значит, проблема в правах пользователя USR1CV8. Если регламентное задание сработает, а HTTP-сервис нет — проблема в настройках веб-сервера (IIS/Apache).

Важный совет: Всегда проверяйте существование сетевого пути перед началом работы. Помните, что для сервера 1С путь D:\Files и для вас тот же путь — это физически одно и то же место, а сетевой диск Z:\ у сервера может просто не существовать, так как диски монтируются для конкретного пользователя при входе в систему.

← На главную