Обмен НСИ через HTTP-сервисы 1С строится по схеме «мастер-база — приёмники»: мастер-база хранит эталонные справочники (физические лица, подразделения, номенклатуру) и публикует HTTP-сервис, который по запросу отдаёт данные в JSON по заранее описанному контракту полей. Приёмники по расписанию забирают изменения порциями, подтверждают получение и записывают объекты по уникальному идентификатору, поэтому повторная загрузка не плодит дубли.
В одной из реализаций такую логику оформляют подсистемой «домены данных»: каждый домен — это справочник-источник, запрос выборки и контракт полей, настраиваемые в отдельном справочнике. Ниже — архитектура такого обмена, код ключевых частей и решения, которые делают его надёжным: регистрация изменений через план обмена, курсор, подтверждение и идемпотентная запись.
Когда REST-обмен НСИ лучше типового
| Сценарий | Что выбрать |
|---|---|
| Документы и связанные данные между типовыми конфигурациями 1С | Типовой обмен (конвертация данных, правила обмена) |
| Раздача нескольких справочников из одной базы в 3–10 систем | REST-обмен НСИ по контракту |
| Есть приёмники не на 1С (сайт, портал, кадровая система) | REST-обмен — им нужен только JSON |
| Десятки систем, гарантированная доставка, маршрутизация | Интеграционная шина |
Сильная сторона REST-обмена — прозрачность: любой разработчик видит, какие поля уходят, может проверить ответ сервиса в браузере или Postman и добавить поле, не трогая правила конвертации.
Архитектура: домены данных

Домен данных — единица обмена: «физические лица», «подразделения», «номенклатура». Для каждого домена описываются:
- источник и запрос выборки;
- контракт — состав и формат полей;
- приёмники, которым домен нужен.
В мастер-базе это удобно хранить в справочнике доменов (с текстом запроса и настройками), в приёмниках — в справочнике с адресом мастер-базы, учётными данными и датой последней успешной синхронизации. Структура справочника в мастер-базе и в приёмниках разная: мастер знает, как отдавать, приёмник — откуда и что забирать.
Контракт данных
Контракт описывается в одном месте кода — функцией, возвращающей структуру с полями и значениями по умолчанию. Так сериализация, документация и тесты опираются на один источник.
// Контракт домена «Физические лица», версия 1.
//
// Возвращаемое значение:
// Структура:
// * uuid - Строка - уникальный идентификатор ссылки
// * name - Строка - полное наименование
// * deleted - Булево - пометка удаления
// * lastName, firstName, patronymic - Строка - ФИО
// * birthDate - Строка, Неопределено - дата рождения в ISO 8601 или null
// * email - Строка - адрес электронной почты
//
Функция КонтрактФизическиеЛица() Экспорт
Контракт = Новый Структура;
Контракт.Вставить("uuid", "");
Контракт.Вставить("name", "");
Контракт.Вставить("deleted", Ложь);
Контракт.Вставить("lastName", "");
Контракт.Вставить("firstName", "");
Контракт.Вставить("patronymic", "");
Контракт.Вставить("birthDate", Неопределено);
Контракт.Вставить("email", "");
Возврат Контракт;
КонецФункцииПравила, которые я закладываю в контракт с первого дня:
- Имена полей — латиница в camelCase. Приёмники не на 1С скажут спасибо.
- Даты — ISO 8601, пустая дата —
null. Строка «0001-01-01» в приёмнике станет ошибкой или мусором. - Строки без хвостовых пробелов. Значения из реквизитов фиксированной длины обрезайте
СокрЛП, иначе в JSON уходят строки с пробелами, а в приёмнике появляются «разные» одинаковые значения. - Ссылки — через uuid. Никаких представлений вместо ссылок.
- Версия в адресе (
/v1/). Новое обязательное поле или смена формата — новая версия; добавление необязательного поля совместимо.
Мастер-база: регистрация изменений
Отдавать весь справочник при каждом опросе дорого. Надёжный способ знать, что изменилось для конкретного приёмника, — план обмена: по узлу на приёмник, справочники домена включены в состав плана с авторегистрацией. Платформа сама регистрирует изменения объектов для каждого узла, а таблица изменений доступна в запросе.
ВЫБРАТЬ ПЕРВЫЕ 100
Изменения.Ссылка КАК Ссылка,
Изменения.Ссылка.Наименование КАК Наименование,
Изменения.Ссылка.ПометкаУдаления КАК ПометкаУдаления,
Изменения.Ссылка.Фамилия КАК Фамилия,
Изменения.Ссылка.Имя КАК Имя,
Изменения.Ссылка.Отчество КАК Отчество,
Изменения.Ссылка.ДатаРождения КАК ДатаРождения,
Изменения.Ссылка.ЭлектроннаяПочта КАК ЭлектроннаяПочта
ИЗ
Справочник.ФизическиеЛица.Изменения КАК Изменения
ГДЕ
Изменения.Узел = &УзелИмена реквизитов справочника условные — в типовых конфигурациях часть данных хранится в контактной информации и регистрах, и запрос будет сложнее.
Порция ограничена ПЕРВЫЕ 100. Приёмник обработал порцию — присылает подтверждение со списком uuid, мастер-база удаляет регистрацию:
Процедура ПодтвердитьПолучение(Узел, МассивИдентификаторов) Экспорт
Для Каждого Идентификатор Из МассивИдентификаторов Цикл
Ссылка = Справочники.ФизическиеЛица.ПолучитьСсылку(Новый УникальныйИдентификатор(Идентификатор));
ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Ссылка);
КонецЦикла;
КонецПроцедурыЭто лучше, чем курсор по дате изменения: не теряются изменения, сделанные в ту же секунду, и не важно, совпадает ли время на серверах. Если объект снова изменят после выдачи, но до подтверждения, платформа зарегистрирует его повторно и приёмник получит свежую версию в следующей порции.
Мастер-база: обработчик HTTP-сервиса
Сервис с корневым URL nsi и шаблоном /v1/{domain}/changes: GET отдаёт порцию, POST на /v1/{domain}/ack — подтверждение. Обработчик GET:
Функция ИзмененияGET(Запрос)
ИмяДомена = Запрос.ПараметрыURL.Получить("domain");
Узел = ОбменНСИСервер.УзелТекущегоПользователя(); // узел приёмника по пользователю сеанса
Если Узел = Неопределено Тогда
Возврат ОбменНСИСервер.ОтветJSON(403, Новый Структура("error", "Приёмник не зарегистрирован"));
КонецЕсли;
Попытка
Лимит = ОбменНСИСервер.ЛимитИзЗапроса(Запрос, 100, 1000);
Порция = ОбменНСИСервер.ПорцияИзменений(ИмяДомена, Узел, Лимит);
Исключение
ЗаписьЖурналаРегистрации("ОбменНСИ.Выгрузка", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат ОбменНСИСервер.ОтветJSON(500, Новый Структура("error", "Ошибка формирования данных"));
КонецПопытки;
Тело = Новый Структура;
Тело.Вставить("result", Порция.Данные);
Тело.Вставить("hasMore", Порция.ЕстьЕще);
Возврат ОбменНСИСервер.ОтветJSON(200, Тело);
КонецФункцииДетали, которые здесь важны:
- Узел определяется по пользователю, под которым пришёл запрос, а не по параметру URL. Иначе приёмник может «подсмотреть» чужие изменения.
- Лимит проверяется и ограничивается сверху: клиент не должен иметь возможность запросить миллион записей.
- Признак
hasMoreвычисляется выборкойПЕРВЫЕ Лимит + 1: если пришло больше лимита, лишняя запись отбрасывается, а приёмник знает, что нужно запросить ещё. - Запрос домена не собирается конкатенацией значений. Если приёмник может передавать фильтры, имена полей сверяйте со списком разрешённых, а значения передавайте только параметрами запроса.
Заполнение контракта из строки выборки:
Функция ЭлементКонтракта(Выборка)
Элемент = КонтрактФизическиеЛица();
Элемент.uuid = Строка(Выборка.Ссылка.УникальныйИдентификатор());
Элемент.name = СокрЛП(Выборка.Наименование);
Элемент.deleted = Выборка.ПометкаУдаления;
Элемент.lastName = СокрЛП(Выборка.Фамилия);
Элемент.firstName = СокрЛП(Выборка.Имя);
Элемент.patronymic = СокрЛП(Выборка.Отчество);
Элемент.email = СокрЛП(Выборка.ЭлектроннаяПочта);
Если ЗначениеЗаполнено(Выборка.ДатаРождения) Тогда
Элемент.birthDate = ЗаписатьДатуJSON(Выборка.ДатаРождения, ФорматДатыJSON.ISO);
КонецЕсли;
Возврат Элемент;
КонецФункцииПриёмник: забрать, записать, подтвердить
В приёмнике одно регламентное задание с параметром — именем домена (или по заданию на домен). Цикл: запросить порцию → записать объекты → подтвердить → повторять, пока hasMore.
Функция ЗапроситьПорцию(Соединение, ИмяДомена, Лимит)
HTTPЗапрос = Новый HTTPЗапрос(СтрШаблон("/master/hs/nsi/v1/%1/changes?limit=%2", ИмяДомена, Формат(Лимит, "ЧГ=")));
HTTPЗапрос.Заголовки.Вставить("Accept", "application/json");
Ответ = Соединение.Получить(HTTPЗапрос);
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение СтрШаблон("Мастер-база вернула код %1: %2", Ответ.КодСостояния,
Лев(Ответ.ПолучитьТелоКакСтроку(), 500));
КонецЕсли;
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
Возврат ПрочитатьJSON(Чтение, , "birthDate", ФорматДатыJSON.ISO);
КонецФункцииСоединение создаётся один раз на весь сеанс синхронизации, с HTTPS и таймаутом:
Соединение = Новый HTTPСоединение(АдресСервера, 443, Логин, Пароль, , 60, Новый ЗащищенноеСоединениеOpenSSL);Логин и пароль не храните открытым текстом в реквизитах справочника — в конфигурациях на БСП для этого есть безопасное хранилище (ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище и ПрочитатьДанныеИзБезопасногоХранилища).
Идемпотентная запись по uuid
Процедура ЗаписатьФизическоеЛицо(Данные)
Ссылка = Справочники.ФизическиеЛица.ПолучитьСсылку(Новый УникальныйИдентификатор(Данные.uuid));
Объект = Ссылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
Объект = Справочники.ФизическиеЛица.СоздатьЭлемент();
Объект.УстановитьСсылкуНового(Ссылка);
КонецЕсли;
Объект.Наименование = Данные.name;
Объект.Фамилия = Данные.lastName;
Объект.Имя = Данные.firstName;
Объект.Отчество = Данные.patronymic;
Объект.ДатаРождения = ?(Данные.birthDate = Неопределено, Дата(1, 1, 1), Данные.birthDate);
Объект.ПометкаУдаления = Данные.deleted;
Объект.ОбменДанными.Загрузка = Истина;
Объект.Записать();
КонецПроцедурыСсылка в приёмнике совпадает со ссылкой в мастер-базе — это упрощает любые последующие сверки и обмены. ОбменДанными.Загрузка = Истина отключает проверки и бизнес-логику при записи; используйте его осознанно, если в приёмнике при записи справочника должна срабатывать своя логика — не включайте.
Подтверждение отправляйте только после успешной записи всей порции. Если запись упала на середине — не подтверждайте: мастер отдаст ту же порцию ещё раз, а идемпотентная запись не создаст дублей.
Типичные ошибки
- Курсор по дате изменения. Теряет изменения в пределах одной секунды и зависит от часов серверов. Используйте регистрацию изменений.
- Хвостовые пробелы и пустые даты в JSON. Приёмник получает «грязные» данные.
- Поиск в приёмнике по наименованию или коду. Переименование в мастер-базе создаёт дубль. Только uuid.
- Сборка текста запроса из параметров URL. Прямой путь к ошибкам и утечке данных.
- Новое соединение на каждый запрос. Лишние TLS-рукопожатия и медленная синхронизация.
- Подтверждение до записи. При сбое данные потеряны: мастер уже считает их доставленными.
Обмен НСИ надёжен тогда, когда любую порцию можно безопасно получить дважды. Регистрация изменений, подтверждение и запись по uuid дают именно это.
Проектирую и запускаю такие обмены в рамках услуг обмен между базами 1С и интеграция 1С по API.
Итог
- Мастер-база отдаёт справочники в JSON по контракту, описанному в одном месте и версионированному.
- Изменения для каждого приёмника отслеживаются планом обмена; регистрация снимается после подтверждения.
- Порции ограничиваются лимитом, признак продолжения вычисляется выборкой на одну запись больше.
- Приёмник пишет объекты по uuid через
ПолучитьСсылкуиУстановитьСсылкуНового— повторы не создают дублей. - Учётные данные — в безопасном хранилище, соединение — HTTPS с таймаутом и переиспользованием.




