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

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

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

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

Чем HTTP-сервисы отличаются от Web-сервисов (SOAP)?

Прежде чем перейти к практике, давайте проанализируем ключевые преимущества HTTP-сервисов перед традиционными SOAP-службами:

  1. Простота и лаконичность. Вместо сложных XML-схем (WSDL, XDTO) в HTTP-сервисах используются стандартные методы протокола HTTP (GET, POST, PUT, DELETE).
  2. Минимальный оверхед (трафик). Данные обычно передаются в формате JSON, который намного легче и проще для парсинга, чем громоздкий XML.
  3. Универсальность. HTTP-сервис базы 1С может легко взаимодействовать не только с другой базой 1С, но и с мобильными приложениями, сайтами, CRM-системами и любыми внешними сервисами.

Шаг 1. Обеспечение отзывчивости интерфейса (Асинхронность в УФ)

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

Начиная с версии платформы 1С:Предприятие 8.3.21, разработчикам доступны встроенные асинхронные методы для работы с объектом HTTPСоединение. Эти методы работают на основе механизма обещаний (конструкции Асинх и Ждать). Они позволяют отправлять HTTP-запросы в фоновом режиме без блокировки работы пользователя.

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


&НаКлиенте
АсинхроннаяПроцедура ВыполнитьОтправкуДанныхАсинх()
    
    // Создаем защищенное SSL-соединение
    SSLСоединение = Новый ЗащищенноеСоединениеOpenSSL();
    
    // Настраиваем параметры подключения к базе-приемнику
    Соединение = Новый HTTPСоединение("exchange.mycompany.ru", , "Администратор", "Пароль123", , 30, SSLСоединение);
    
    Запрос = Новый HTTPЗапрос("/exchange_api/v1/put_data");
    Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    
    // Формируем простое тело запроса для проверки связи
    СтрокаОтправки = "{""status"":""ping"", ""database"":""UT""}";
    Запрос.УстановитьТелоИзСтроки(СтрокаОтправки, КодировкаТекста.UTF8, ИспользованиеБом.НеИспользовать);
    
    Попытка
        // Используем оператор Ждать для асинхронного вызова метода POST
        Ответ = Ждать Соединение.ВызватьHTTPМетодАсинх("POST", Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            ПоказатьПредупреждение(, "Данные успешно отправлены и приняты сервером!");
        Иначе
            ПоказатьПредупреждение(, "Ошибка сервера. Код состояния: " + Ответ.КодСостояния);
        КонецЕсли;
    Исключение
        ПоказатьПредупреждение(, "Не удалось установить связь с сервером обмена.");
    КонецПопытки;
    
КонецПроцедуры

Если ваша платформа ниже версии 8.3.21, или если объем передаваемых данных велик и требует длительной обработки, лучшим паттерном будет перенос отправки в фоновое задание на сервере. Клиентская форма запускает фоновое задание через ФоновыеЗадания.Выполнить(), а сама лишь периодически опрашивает его статус, выводя пользователю прогресс-бар или индикатор ожидания.


Шаг 2. Форматирование данных: Сериализация в JSON

При обмене через HTTP-сервисы стандартным форматом передачи сообщений является JSON. Платформа 1С предоставляет высокопроизводительные потоковые механизмы для работы с этим форматом. Разберем по шагам, как сериализовать объект или структуру данных 1С в строку JSON.

Для быстрой сериализации массивов, структур, таблиц значений и соответствий мы используем встроенную процедуру ЗаписатьJSON(). Посмотрим на практический пример формирования пакета данных для выгрузки элемента справочника:


&НаСервереБезКонтекста
Функция СформироватьПакетДанныхНоменклатуры(СсылкаНаНоменклатуру)
    
    // Собираем данные в структуру
    ДанныеНоменклатуры = Новый Структура;
    ДанныеНоменклатуры.Вставить("UUID", Строка(СсылкаНаНоменклатуру.УникальныйИдентификатор()));
    ДанныеНоменклатуры.Вставить("Наименование", СсылкаНаНоменклатуру.Наименование);
    ДанныеНоменклатуры.Вставить("Артикул", СсылкаНаНоменклатуру.Артикул);
    ДанныеНоменклатуры.Вставить("Штрихкод", ПолучитьШтрихкодНоменклатуры(СсылкаНаНоменклатуру));
    
    // Сериализуем структуру в строку JSON
    ЗаписьJSON = Новый ЗаписьJSON;
    НастройкиЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
    ЗаписьJSON.УстановитьСтроку(НастройкиЗаписи);
    
    ЗаписатьJSON(ЗаписьJSON, ДанныеНоменклатуры);
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    Возврат СтрокаJSON;
    
КонецФункции

Шаг 3. Создание HTTP-сервиса на стороне базы-приемника

Теперь разработаем принимающую сторону. В базе-приемнике нам необходимо создать новый объект конфигурации HTTP-сервис.

Зададим следующие свойства для нашего нового сервиса:

Внутри сервиса создадим шаблон URL:

Для этого шаблона добавим метод POST и свяжем его с обработчиком в модуле HTTP-сервиса.

Критически важный архитектурный момент: Не пытайтесь проводить тяжелые документы и выполнять сложную бизнес-логику непосредственно внутри транзакции вызова HTTP-метода. Если база-приемник в этот момент заблокирует таблицы или обработка займет более 30 секунд, отправитель получит ошибку таймаута (например, 504 Gateway Timeout). Безопасный подход заключается в использовании очереди сообщений.

Проанализируем правильный шаблон обработчика HTTP-сервиса, который быстро сохраняет входящий пакет в очередь (регистр сведений) и возвращает статус 200 OK:


Функция v1_put_dataPOST(Запрос)
    
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    
    // Читаем входящую строку JSON
    ТелоЗапроса = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
    
    Если ПустаяСтрока(ТелоЗапроса) Тогда
        Ответ.КодСостояния = 400; // Bad Request
        Ответ.УстановитьТелоИзСтроки("{""error"":""Тело запроса не может быть пустым""}", КодировкаТекста.UTF8);
        Возврат Ответ;
    КонецЕсли;
    
    Попытка
        // Быстро записываем сырые данные во входящую очередь (Регистр Сведений)
        НачатьТранзакцию();
        
        МенеджерЗаписи = РегистрыСведений.ОчередьВходящихПакетовHTTP.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.ИдентификаторПакета = Строка(Новый УникальныйИдентификатор);
        МенеджерЗаписи.ДатаПолучения = ТекущаяДатаСеанса();
        МенеджерЗаписи.ТелоПакета = ТелоЗапроса;
        МенеджерЗаписи.СтатусОбработки = Перечисления.СтатусыПакетов.Новый;
        МенеджерЗаписи.Записать();
        
        ЗафиксироватьТранзакцию();
        
        // Моментально сообщаем отправителю, что пакет принят в обработку
        ОтветСтрока = "{""success"":true,""message"":""Пакет успешно зарегистрирован в очереди""}";
        Ответ.УстановитьТелоИзСтроки(ОтветСтрока, КодировкаТекста.UTF8);
        
    Исключение
        ОтменитьТранзакцию();
        
        // В случае критической внутренней ошибки сервера возвращаем 500 статус
        Ответ.КодСостояния = 500;
        ОшибкаОписание = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
        ОтветСтрока = "{""success"":false,""error"":""" + ОшибкаОписание + """}";
        Ответ.УстановитьТелоИзСтроки(ОтветСтрока, КодировкаТекста.UTF8);
        
        ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Ошибка, , , ОшибкаОписание);
    КонецПопытки;
    
    Возврат Ответ;
    
КонецФункции

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


Шаг 4. Интеграция с Планами Обмена на источнике

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

Рассмотрим сценарий работы регламентного задания выгрузки на стороне базы-источника:

  1. При изменении объектов в базе-источнике они автоматически регистрируются на узле нашего плана обмена.
  2. Регламентное задание выбирает зарегистрированные изменения порциями.
  3. Пакет сериализуется в JSON и отправляется на HTTP-сервис базы-приемника.
  4. Важно: Удаление регистрации изменений на узле источника происходит только в том случае, если HTTP-сервис приемника вернул успешный статус ответа 200 OK.

Посмотрим, как выглядит программный код выгрузки изменений с контролем доставки:


Процедура ВыполнитьВыгрузкуЗарегистрированныхИзменений() Экспорт
    
    УзелПриемник = ПланыОбмена.ОбменЧерезHTTP.НайтиПоКоду("BASE_PR");
    Если УзелПриемник.Пустая() Тогда
        ВызватьИсключение "Не найден узел плана обмена для базы-приемника!";
    КонецЕсли;
    
    // Выбираем изменения порциями по 50 объектов
    ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелПриемник, 50);
    
    МассивИзменений = Новый Массив;
    СписокОбъектовДляУдаленияРегистрации = Новый Массив;
    
    Пока ВыборкаИзменений.Следующий() Цикл
        ДанныеОбъекта = ВыборкаИзменений.Получить();
        Если ДанныеОбъекта = Неопределено Тогда
            Продолжить;
        КонецЕсли;
        
        // Преобразуем объект 1С в структуру для JSON
        СтруктураОбъекта = ПреобразоватьОбъектВСтруктуру(ДанныеОбъекта);
        МассивИзменений.Добавить(СтруктураОбъекта);
        СписокОбъектовДляУдаленияРегистрации.Добавить(ДанныеОбъекта);
    КонецЦикла;
    
    Если МассивИзменений.Количество() = 0 Тогда
        Возврат; // Нечего отправлять
    КонецЕсли;
    
    // Сериализуем весь массив объектов в один JSON-пакет
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, МассивИзменений);
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    // Отправляем на приемник
    SSL = Новый ЗащищенноеСоединениеOpenSSL();
    Соединение = Новый HTTPСоединение("exchange.mycompany.ru", , "ExchangeUser", "SecretPassword", , 45, SSL);
    Запрос = Новый HTTPЗапрос("/exchange_api/v1/put_data");
    Запрос.Заголовки.Вставить("Content-Type", "application/json");
    Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеБом.НеИспользовать);
    
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            // Подтверждение получено! Очищаем регистрацию изменений на источнике
            ПланыОбмена.УдалитьРегистрациюИзменений(УзелПриемник, СписокОбъектовДляУдаленияРегистрации);
            ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Информация, , , 
                "Успешно отправлен пакет. Объектов: " + Строка(МассивИзменений.Количество()));
        Иначе
            ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Предупреждение, , , 
                "Приемник вернул код ошибки: " + Ответ.КодСостояния);
        КонецЕсли;
    Исключение
        ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Ошибка, , , 
            "Ошибка отправки данных: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

Шаг 5. Публикация и безопасность решения

Чтобы база-приемник могла принимать HTTP-запросы, ее необходимо опубликовать на веб-сервере (Apache или IIS). При публикации обязательно проверьте, что в окне настроек публикации на вкладке "HTTP сервисы" отмечен флажком ваш созданный сервис ОбменДанными.

Для обеспечения промышленного уровня безопасности соблюдайте следующие правила:

  1. Используйте только HTTPS. Всегда настраивайте веб-сервер на использование SSL-сертификатов (например, бесплатных Let's Encrypt). Передача авторизационных данных по открытому каналу HTTP недопустима.
  2. Выделенный пользователь 1С. Создайте в базе-приемнике отдельного пользователя 1С (например, ExchangeUser) с минимально достаточными правами для записи в регистр очереди. Отключите для этого пользователя показ в списке выбора при старте программы.
  3. Настройка веб-сервера. Ограничьте доступ к URL вашего API на уровне веб-сервера (разрешите доступ только со статического IP-адреса сервера-источника).

Мы спроектировали базовую архитектуру, гарантирующую быструю и отказоустойчивую передачу пакетов с отложенной обработкой, что минимизирует риски блокировок базы и потери данных в случае сетевых сбоев.

← На главную