Как правильно передать файл на веб-сервер 1С по HTTP-соединению?

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

При работе с веб-сервисами и интеграциями часто возникает задача передать файл из одной системы в другую по HTTP. Если в качестве приемника выступает информационная база 1С, опубликованная на веб-сервере (например, Apache или IIS), многие разработчики совершают одну и ту же логическую ошибку. Они предполагают, что достаточно отправить POST-запрос с файлом на URL публикации, и веб-сервер сам догадается сохранить этот файл в своем каталоге. Это не так.

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

В чем заключается основная ошибка?

Проанализируем ситуацию изначального автора. Он отправил HTTP-запрос на адрес localhost/post_test, где post_test — это имя публикации. Автор ожидал, что отправленный файл отправка.txt автоматически появится в каталоге публикации D:\web. Однако этого не произошло.

Ключевое заблуждение заключается в том, что отправка данных на URL опубликованной базы не означает отправку файла напрямую веб-серверу для сохранения на диске. Этот запрос на самом деле адресуется приложению 1С. Веб-сервер (Apache) в данном случае выступает лишь в роли посредника: он принимает запрос и передает его на обработку серверу 1С. А сервер 1С, в свою очередь, "не знает", что делать с этим запросом, если для него не написан специальный обработчик. Без такого обработчика запрос просто игнорируется, и никакого сохранения файла не происходит.

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

Правильный подход: используем HTTP-сервисы 1С

HTTP-сервис — это объект конфигурации, который позволяет создать в 1С собственный API, способный принимать и обрабатывать HTTP-запросы. Решение нашей задачи состоит из двух частей: создание серверной части (HTTP-сервис, который примет и сохранит файл) и доработка клиентской части (код, который правильно отправит файл на адрес этого сервиса).

Шаг 1: Реализация серверной части (прием файла)

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

  1. Откройте конфигуратор базы-приемника.
  2. В дереве конфигурации найдите ветку Общие -> HTTP-сервисы.
  3. Создайте новый HTTP-сервис, например, с именем ФайловыйОбмен.
  4. Укажите Корневой URL для сервиса, например, fileapi. Это имя будет частью адреса, по которому мы будем обращаться к нашему сервису.
  5. Внутри сервиса создайте новый Шаблон URL. Шаблон определяет конкретные адреса и методы, на которые будет реагировать сервис.
    • Задайте Шаблон, например, /upload. Этот шаблон можно сделать более динамичным, например, /upload/{FileName}, чтобы передавать имя файла прямо в URL.
    • Создайте для этого шаблона Метод. Укажите Имя (например, ЗагрузитьФайл) и HTTP-метод (POST, так как мы передаем данные на сервер).
  6. Дважды щелкните по созданному методу, и система создаст процедуру-обработчик в модуле HTTP-сервиса. Именно здесь мы и напишем код для приема файла.

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

Посмотрим на пример кода для модуля HTTP-сервиса:


Функция ЗагрузитьФайл(Запрос)

    // Определяем путь, куда будем сохранять файл.
    // ВАЖНО: у пользователя, от имени которого работает сервер 1С, 
    // должны быть права на запись в этот каталог!
    ПутьСохранения = "D:\web\uploads\";

    // Проверяем, существует ли каталог, и если нет - создаем его
    Попытка
        СоздатьКаталог(ПутьСохранения);
    Исключение
        // Если не удалось создать каталог, возвращаем ошибку 500
        Ответ = Новый HTTPСервисОтвет(500);
        ТекстОшибки = "Ошибка на сервере: не удалось создать каталог для загрузки файлов. " + ОписаниеОшибки();
        Ответ.УстановитьТелоИзСтроки(ТекстОшибки, КодировкаТекста.UTF8);
        Возврат Ответ;
    КонецПопытки;
    
    // Получаем имя файла из параметра URL. 
    // Это работает, если шаблон URL у нас, например, "/upload/{FileName}"
    ИмяФайла = Запрос.ПараметрыURL.Получить("FileName");
    
    // Если имя файла не передано в URL, можно сгенерировать уникальное имя
    Если ИмяФайла = Неопределено Тогда
        ИмяФайла = Строка(Новый УникальныйИдентификатор()) + ".dat";
    КонецЕсли;
    
    ПолныйПутьКФайлу = ПутьСохранения + ИмяФайла;
    
    // Получаем тело запроса как двоичные данные. 
    // Это самый эффективный способ для работы с файлами.
    ДвоичныеДанныеФайла = Запрос.ПолучитьТелоКакДвоичныеДанные();
    
    // Записываем полученные данные в файл на сервере
    Попытка
        ДвоичныеДанныеФайла.Записать(ПолныйПутьКФайлу);
    Исключение
        // Если не удалось записать файл, возвращаем ошибку 500
        Ответ = Новый HTTPСервисОтвет(500);
        ТекстОшибки = "Ошибка на сервере: не удалось сохранить файл. " + ОписаниеОшибки();
        Ответ.УстановитьТелоИзСтроки(ТекстОшибки, КодировкаТекста.UTF8);
        Возврат Ответ;
    КонецПопытки;
    
    // Если все прошло успешно, формируем ответ с кодом 200 (OK)
    Ответ = Новый HTTPСервисОтвет(200);
    ТекстОтвета = "Файл успешно сохранен на сервере по пути: " + ПолныйПутьКФайлу;
    Ответ.УстановитьТелоИзСтроки(ТекстОтвета, КодировкаТекста.UTF8);
    
    Возврат Ответ;

КонецФункции

После написания кода не забудьте обновить публикацию на веб-сервере, чтобы изменения вступили в силу. Теперь наш сервер готов принимать файлы по адресу: http://имя_сервера/имя_публикации/hs/fileapi/upload/имя_файла.txt.

Шаг 2: Реализация клиентской части (отправка файла)

Теперь доработаем код на стороне клиента, чтобы он отправлял файл на правильный адрес и в правильном формате.

Основная задача клиента — прочитать файл с диска в двоичные данные и установить эти данные в тело HTTP-запроса.

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


&НаКлиенте
Процедура ОтправитьФайлНаСервер()

    // Параметры для отправки
    АдресСервера = "localhost"; // или IP-адрес сервера
    ИмяПубликации = "post_test";
    ПутьКФайлуНаКлиенте = "C:\temp\отправка.txt";
    
    // Извлекаем имя файла из полного пути
    ФайлНаКлиенте = Новый Файл(ПутьКФайлуНаКлиенте);
    ИмяФайлаДляURL = ФайлНаКлиенте.Имя; // "отправка.txt"
    
    // Формируем полный адрес ресурса нашего HTTP-сервиса
    // Структура: /<ИмяПубликации>/hs/<КорневойURL_сервиса>/<ШаблонURL>
    АдресРесурса = СтрШаблон("/%1/hs/fileapi/upload/%2", ИмяПубликации, ИмяФайлаДляURL);
    // Получится что-то вроде "/post_test/hs/fileapi/upload/отправка.txt"
    
    // Читаем файл в двоичные данные
    Попытка
        ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлуНаКлиенте);
    Исключение
        Сообщить("Не удалось прочитать файл: " + ПутьКФайлуНаКлиенте);
        Возврат;
    КонецПопытки;
    
    // Создаем HTTP-запрос
    Запрос = Новый HTTPЗапрос(АдресРесурса);
    
    // Устанавливаем двоичные данные файла как тело запроса
    Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеФайла);
    
    // Устанавливаем заголовок Content-Type. Для бинарных данных
    // лучше всего подходит application/octet-stream
    Запрос.Заголовки.Вставить("Content-Type", "application/octet-stream");
    
    // Устанавливаем соединение и отправляем запрос
    Попытка
        // Если сервер использует HTTPS, нужно будет указать МенеджерБезопасности
        Соединение = Новый HTTPСоединение(АдресСервера);
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        
        // Анализируем ответ от сервера
        Если Ответ.КодСостояния = 200 Тогда
            Сообщить("Успех! Ответ сервера: " + Ответ.ПолучитьТелоКакСтроку());
        Иначе
            Сообщить("Ошибка! Код состояния: " + Ответ.КодСостояния);
            Сообщить("Тело ответа: " + Ответ.ПолучитьТелоКакСтроку());
        КонецЕсли;
        
    Исключение
        Сообщить("Не удалось выполнить HTTP-запрос. " + ОписаниеОшибки());
    КонецПопытки;

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

Теперь при выполнении этой процедуры файл C:\temp\отправка.txt будет прочитан, отправлен на наш HTTP-сервис и сохранен сервером 1С в каталоге D:\web\uploads\.

Выводы

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

  1. Нельзя просто отправить файл на URL публикации и ожидать его автоматического сохранения. Веб-сервер лишь транслирует запрос приложению 1С.
  2. Нужно создать на стороне приемника HTTP-сервис, который будет "слушать" определенный URL и обрабатывать входящие POST-запросы.
  3. В обработчике HTTP-сервиса на сервере используйте метод Запрос.ПолучитьТелоКакДвоичныеДанные() для получения содержимого файла.
  4. На клиенте читайте файл в объект ДвоичныеДанные и устанавливайте его в тело запроса через метод Запрос.УстановитьТелоИзДвоичныхДанных().
  5. Важно помнить о правах доступа. Пользователь операционной системы, от имени которого работает сервер 1С, должен иметь права на запись в каталог, куда вы планируете сохранять файлы.

Этот подход является стандартным и надежным способом организации файлового обмена с информационными базами 1С через HTTP.

← На главную