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

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

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

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

Постановка задачи и архитектура решения

Нам необходимо обрабатывать URL вида: ip-адрес/bin/get_file.php?kusok=1000&id=1234567890123. Несмотря на расширение .php в адресе, мы можем настроить веб-сервер (Apache или IIS) таким образом, чтобы эти запросы перенаправлялись в 1С. Основная логика должна работать следующим образом:

  1. Первое обращение: Отправляется файл, номер которого соответствует параметру kusok.
  2. Повторные обращения: Если id тот же, система должна увеличивать номер файла на 1 относительно предыдущего выданного, игнорируя параметр kusok в URL (до тех пор, пока он не изменится принудительно).
  3. Разделение сессий: Для разных id ведутся независимые счетчики.
  4. Сброс по таймауту: Если между запросами прошло более 90 секунд, последовательность сбрасывается, и отсчет начинается заново с параметра kusok.

Шаг 1: Подготовка структуры данных в 1С

Для хранения состояния сессий нам понадобятся два регистра сведений. Разберем их назначение:

1. Регистр сведений "СессииУстройств" (периодический, в пределах секунды):

Здесь мы будем фиксировать сам факт обращения. - Измерение: ИдентификаторУстройства (Строка). - Ресурс: ДатаПоследнегоЗапроса (Дата/Время). Этот регистр позволит нам определять, не "протухла" ли сессия (прошло ли более 1.5 минут).

2. Регистр сведений "СостояниеВыдачи":

Здесь хранится информация о том, какой файл был выдан последним. - Измерение: ИдентификаторУстройства (Строка). - Ресурс: ПоследнийНомерФайла (Число). - Ресурс: ТекущийКусок (Число) — для отслеживания изменения базового параметра в URL.

Шаг 2: Создание HTTP-сервиса

В дереве метаданных 1С создадим новый объект HTTP-сервис. Назовем его, например, FileProvider. В поле "Корневой URL" укажем bin.

Добавим шаблон URL: get_file.php. Внутри шаблона создадим метод GET и назначим ему обработчик в модуле сервиса. Проанализируем пример кода для этого обработчика:


Функция get_file_GET(Запрос)
    
    Параметры = Запрос.ПараметрыЗапроса;
    ID_Устройства = Параметры.Получить("id");
    НачальныйКусок = Число(Параметры.Получить("kusok"));
    
    ТекущаяДата = ТекущаяДата();
    ВремяТаймаута = 90; // 1.5 минуты
    
    // 1. Проверяем таймаут сессии
    ЗапросСессии = Новый Запрос;
    ЗапросСессии.Текст = 
        "ВЫБРАТЬ
        |   Сессии.Период КАК ПоследняяДата
        |ИЗ
        |   РегистрСведений.СессииУстройств.СрезПоследних(, ИдентификаторУстройства = &ID) КАК Сессии";
    ЗапросСессии.УстановитьПараметр("ID", ID_Устройства);
    Выборка = ЗапросСессии.Выполнить().Выбрать();
    
    НужноНачатьЗаново = Истина;
    Если Выборка.Следующий() Тогда
        Если (ТекущаяДата - ВыборкаПоследняяДата) < ВремяТаймаута Тогда
            НужноНачатьЗаново = Ложь;
        КонецЕсли;
    КонецЕсли;
    
    // 2. Определяем номер файла
    НомерДляВыдачи = 0;
    
    Если НужноНачатьЗаново Тогда
        НомерДляВыдачи = НачальныйКусок;
    Иначе
        // Читаем из регистра СостояниеВыдачи
        // Если НачальныйКусок изменился в URL, тоже начинаем заново
        // Код получения из СостояниеВыдачи...
        // НомерДляВыдачи = ПоследнийНомер + 1;
    КонецЕсли;
    
    // 3. Формируем ответ
    ПутьКФайлу = ПолучитьПутьКФайлу(НомерДляВыдачи);
    
    Ответ = Новый HTTPСервисОтвет(200);
    ФайлНаДиске = Новый Файл(ПутьКФайлу);
    Если ФайлНаДиске.Существует() Тогда
        Ответ.УстановитьТелоИзФайла(ПутьКФайлу);
        Ответ.Заголовки.Вставить("Content-Type", "application/octet-stream");
        
        // Обновляем данные в регистрах
        ЗаписатьСостояние(ID_Устройства, НомерДляВыдачи, НачальныйКусок);
    Иначе
        Ответ.КодСостояния = 404;
    КонецЕсли;
    
    Возврат Ответ;

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

Шаг 3: Оптимизация передачи файлов

Рассмотрим важный аспект: передачу бинарных данных. В ранних версиях платформы 1С разработчикам приходилось считывать файл в память и кодировать его в Base64, что приводило к огромным затратам ресурсов. В современных версиях 8.3 крайне рекомендуется использовать метод УстановитьТелоИзФайла(). Это позволяет платформе передавать поток данных напрямую с диска в HTTP-ответ, минуя создание тяжелых объектов в памяти сервера 1С.

Также важно правильно настроить MIME-тип. Если файлы имеют расширение .dat и предназначены для оборудования, заголовок Content-Type: application/octet-stream будет наиболее универсальным решением.

Альтернативный метод: ASP + COM-соединение

Если по каким-то причинам (например, использование устаревшей версии платформы 8.1 или 8.2 без лицензий на веб-сервисы) вы не можете использовать HTTP-сервисы 1С, существует "гибридный" путь. Вы можете использовать скрипт на языке ASP или PHP, который будет принимать веб-запрос, а затем через COM-соединение (V83.COMConnector) обращаться к 1С для получения логики (какой файл выдать). Рассмотрим пример такого скрипта на ASP:


<%
Dim V8, Conn, kusok, id, fileName
kusok = Request.QueryString("kusok")
id = Request.QueryString("id")

' Подключаемся к 1С
Set V8 = CreateObject("V83.COMConnector")
Set Conn = V8.Connect("Srvr=""ServerName"";Ref=""BaseName"";Usr=""WebUser"";Pwd=""Password"";")

' Вызываем функцию из общего модуля 1С, которая вернет имя файла
fileName = Conn.ОбщийМодульВебСервер.ОпределитьФайл(kusok, id)

' Отдаем файл клиенту
Response.Buffer = False
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 ' adTypeBinary
objStream.Open
objStream.LoadFromFile("C:\FilesCatalog\" & fileName)
Response.ContentType = "application/x-unknown"
Response.BinaryWrite objStream.Read
objStream.Close
%>

Важно: Этот метод значительно медленнее нативных HTTP-сервисов из-за накладных расходов на создание COM-объекта при каждом запросе. Его стоит использовать только как временное или вынужденное решение.

Особенности публикации и производительности

Выясним, как сделать так, чтобы 1С работала быстро и не "тормозила" при каждом обращении. Основная проблема веб-сервисов 1С — время инициализации сеанса. Если при каждом запросе 1С будет заново запускать сеанс пользователя, время ответа составит несколько секунд.

Для решения этой проблемы необходимо настроить пул соединений в файле публикации default.vrd. Разберем ключевые параметры:

Обработка ошибок и статус-коды

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

  1. 404 Not Found: Если файл с вычисленным номером физически отсутствует в каталоге.
  2. 403 Forbidden: Если передан некорректный id или доступ заблокирован.
  3. 500 Internal Server Error: Если произошла ошибка в коде 1С (платформа выдаст её автоматически, если не использовать конструкцию Попытка...Исключение).

Используя объект HTTPСервисОтвет, мы можем гибко управлять этими кодами, что позволит вызывающей стороне (оборудованию) корректно обрабатывать сбои связи или отсутствие данных.

В завершение отметим, что использование 1С в качестве веб-сервера — это мощный инструмент интеграции. Несмотря на то, что специализированные веб-языки (PHP, Go, Python) могут работать быстрее, 1С выигрывает за счет того, что вся бизнес-логика и данные о сессиях находятся в одной базе, что упрощает администрирование и разработку сложных алгоритмов выдачи.

← На главную