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

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

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

Основная идея заключается в том, что механизм планов обмена — это, по сути, логгер изменений. Он фиксирует, какие объекты были изменены, для какого узла (базы-получателя). А вот как вы эти данные будете передавать (через файлы, HTTP, почту) и в каком формате (XML, JSON, CSV) — система 1С не навязывает. Ваша задача — научиться читать этот "лог" и очищать его после успешной отправки данных.

Существует два основных подхода к решению этой задачи.

Подход 1: Упрощенный обмен без строгой нумерации сообщений

Этот метод является наиболее простым и надежным для большинства кастомных обменов, где не требуется строгая последовательность применения сообщений, как в УРБД. Идея в том, чтобы за один сеанс связи отправить все накопившиеся изменения и после подтверждения приема очистить регистрацию.

Шаг 1. Выбираем все зарегистрированные изменения

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

Предположим, мы обмениваемся справочником "Валюты", а узел-получатель у нас записан в переменную УзелПолучателя.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Изменения.Ссылка
    |ИЗ
    |    Справочник.Валюты.Изменения КАК Изменения
    |ГДЕ
    |    Изменения.Узел = &Узел";

Запрос.УстановитьПараметр("Узел", УзелПолучателя);

РезультатЗапроса = Запрос.Выполнить();
ВыборкаИзменений = РезультатЗапроса.Выбрать();

МассивДанныхДляОтправки = Новый Массив;

Пока ВыборкаИзменений.Следующий() Цикл
    // Здесь мы получаем сам объект, чтобы затем его сериализовать в JSON
    ОбъектДляВыгрузки = ВыборкаИзменений.Ссылка.ПолучитьОбъект();
    
    // Формируем структуру, которую легко превратить в JSON
    СтруктураОбъекта = Новый Структура;
    СтруктураОбъекта.Вставить("УникальныйИдентификатор", ОбъектДляВыгрузки.УникальныйИдентификатор());
    СтруктураОбъекта.Вставить("Наименование", ОбъектДляВыгрузки.Наименование);
    СтруктураОбъекта.Вставить("Код", ОбъектДляВыгрузки.Код);
    // ... и другие реквизиты
    
    МассивДанныхДляОтправки.Добавить(СтруктураОбъекта);
КонецЦикла;

На выходе мы получаем массив структур МассивДанныхДляОтправки, готовый к сериализации в JSON и отправке через ваш HTTP-сервис.

Шаг 2. Отправляем данные и получаем подтверждение

Этот шаг у вас уже реализован. Вы сериализуете массив в JSON, отправляете его POST-запросом. Важный момент: принимающая сторона должна не просто вернуть ответ "200 OK", а обработать данные и вернуть список уникальных идентификаторов тех объектов, которые она успешно загрузила. Это защитит от ситуации, когда часть данных загрузилась, а часть — нет из-за ошибки.

Шаг 3. Снимаем регистрацию изменений

После получения ответа со списком успешно принятых объектов, необходимо снять для них регистрацию, чтобы не отправлять их повторно. Делать это нужно точечно, только для тех объектов, по которым пришло подтверждение.

Это позволяет решить проблему, отмеченную на форуме: если во время обмена какой-то объект снова изменится, его регистрация останется, и он попадет в следующую выгрузку.

Для снятия регистрации используется метод ПланыОбмена.УдалитьРегистрациюИзменений().


// Предположим, в переменной ОтветОтСервиса у нас массив ссылок
// на объекты, которые были успешно приняты.
// Эти ссылки нужно найти в базе-отправителе по полученным УИДам.

МассивСсылокДляУдаления = Новый Массив; 
// ... заполняем этот массив ссылками на объекты,
// которые нужно снять с регистрации

Если МассивСсылокДляУдаления.Количество() > 0 Тогда
    ПланыОбмена.УдалитьРегистрациюИзменений(УзелПолучателя, МассивСсылокДляУдаления);
КонецЕсли;

Таким образом, мы удаляем регистрацию только для успешно переданных данных. Если по какому-то объекту подтверждение не пришло, он останется в таблице изменений и будет отправлен в следующий раз.

Подход 2: Классический обмен с номерами сообщений

Этот подход более сложен, так как требует ведения учета номеров отправленных и принятых сообщений. Он гарантирует строгую последовательность применения данных, что критично для систем типа УРБД, но может быть избыточным для простого обмена справочниками.

Шаг 1. Назначаем номер сообщения и выбираем изменения

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


// Получаем узел обмена
УзелПолучателя = ПланыОбмена.МойПланОбмена.НайтиПоКоду("002"); // Пример

// Увеличиваем номер отправленного сообщения
НомерНовогоСообщения = УзелПолучателя.НомерОтправленного + 1;

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


ВыборкаДляСообщения = ПланыОбмена.ВыбратьИзменения(УзелПолучателя, НомерНовогоСообщения);

Шаг 2. Формируем и отправляем сообщение

Теперь нужно обойти эту выборку, чтобы получить данные объектов и сформировать JSON. Процесс аналогичен первому подходу.


МассивДанныхДляОтправки = Новый Массив;

Пока ВыборкаДляСообщения.Следующий() Цикл
    Данные = ВыборкаДляСообщения.Получить(); // Получаем сам объект (справочник, документ и т.д.)
    
    // ... далее логика сериализации данных в структуру ...
    
    МассивДанныхДляОтправки.Добавить(СтруктураОбъекта);
КонецЦикла;

// Отправляем массив и номер сообщения (НомерНовогоСообщения) через HTTP

Шаг 3. Получаем подтверждение и снимаем регистрацию

Принимающая сторона должна не только загрузить данные, но и зафиксировать у себя номер принятого сообщения. В ответ она отправляет подтверждение об успешном приеме сообщения с этим номером.

После получения подтверждения, на стороне отправителя нужно обновить номер отправленного сообщения в узле и снять регистрацию для всего сообщения целиком.


// После получения успешного ответа
УзелОбъект = УзелПолучателя.ПолучитьОбъект();
УзелОбъект.НомерОтправленного = НомерНовогоСообщения;
УзелОбъект.Записать();

// Удаляем регистрацию для всего сообщения
ПланыОбмена.УдалитьРегистрациюИзменений(УзелПолучателя, НомерНовогоСообщения);

Этот метод требует более сложной логики обработки на обеих сторонах и строгой синхронизации номеров. В случае сбоя или потери сообщения, нужно предусматривать механизмы повторной отправки.

Важные моменты при реализации

  1. Транзакционность. На стороне приемника вся операция по разбору JSON и записи объектов в базу данных должна выполняться в рамках одной транзакции. Если при загрузке хотя бы одного объекта возникает ошибка, вся транзакция должна быть отменена. Это гарантирует целостность данных.
  2. Обработка ошибок. Ваш код должен быть готов к сбоям: HTTP-сервис недоступен, сеть пропала, в данных ошибка. Если отправка не удалась или от приемника пришел ответ об ошибке, регистрацию изменений снимать нельзя. Попытку отправки нужно будет повторить позже, например, через регламентное задание.
  3. Идентификаторы объектов. При передаче ссылок на объекты (например, на владельца справочника) в формате JSON, используйте их уникальные идентификаторы (УникальныйИдентификатор()). На принимающей стороне по этому идентификатору вы сможете найти соответствующий объект в базе.

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

← На главную