При работе с веб-сервисами и интеграциями часто возникает задача передать файл из одной системы в другую по 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С собственный API, способный принимать и обрабатывать HTTP-запросы. Решение нашей задачи состоит из двух частей: создание серверной части (HTTP-сервис, который примет и сохранит файл) и доработка клиентской части (код, который правильно отправит файл на адрес этого сервиса).
На стороне конфигурации, которая должна принимать файлы, необходимо создать HTTP-сервис. Разберем по шагам, как это сделать.
ФайловыйОбмен.fileapi. Это имя будет частью адреса, по которому мы будем обращаться к нашему сервису./upload. Этот шаблон можно сделать более динамичным, например, /upload/{FileName}, чтобы передавать имя файла прямо в URL.ЗагрузитьФайл) и HTTP-метод (POST, так как мы передаем данные на сервер).Теперь напишем код обработчика. Наша задача — получить тело входящего запроса, в котором содержатся двоичные данные файла, и сохранить их на диске.
Посмотрим на пример кода для модуля 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.
Теперь доработаем код на стороне клиента, чтобы он отправлял файл на правильный адрес и в правильном формате.
Основная задача клиента — прочитать файл с диска в двоичные данные и установить эти данные в тело 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С через HTTP.