При решении задачи обмена данными между двумя базами 1С, расположенными в разных городах, мы сталкиваемся с необходимостью выбора оптимальной технологии. Этот выбор является критически важным, поскольку он напрямую влияет на стабильность, скорость, безопасность и сложность реализации интеграции. Нам предстоит рассмотреть несколько распространенных подходов, проанализировать их преимущества и недостатки, а также определить, какой из них лучше всего подходит для наших конкретных условий.
Представьте, что у нас есть две различные конфигурации 1С, находящиеся в разных географических точках, и нам требуется регулярно обмениваться небольшими объемами данных, такими как несколько справочников и заявок, пару раз в день. При этом мы планируем самостоятельно заниматься программированием обмена. Давайте разберем основные доступные технологии.
Прежде чем погружаться в детали конкретных технологий, мы должны понять, что нет универсального "лучшего" решения. Выбор всегда зависит от контекста. Подумаем, какие факторы влияют на наш выбор:
Как видите, просто сказать "какую технологию обмена" — это лишь начало. Мы должны определить, что именно будем везти и какие критерии к этому применимы. Все биты одинаковы, но данные, которые ими представлены, могут иметь разную ценность и требования к транспортировке.
Рассмотрим основные технологии, которые обычно используются для организации обмена между базами 1С.
Этот метод является одним из самых простых и понятных. Он основан на передаче файлов, содержащих данные, сериализованные в формат XML, через протокол FTP.
В одной базе 1С мы выгружаем необходимые данные (например, элементы справочников или документы) в XML-файл. Затем этот файл передается на FTP-сервер. Другая база 1С в другом городе подключается к тому же FTP-серверу, скачивает файл и загружает данные из XML в свою информационную базу.
База-источник:
// Создаем объект XMLЗапись
ЗаписьXML = Новый XMLЗапись();
ЗаписьXML.УстановитьИмяФайла("C:\Temp\ДанныеДляОбмена.xml"); // Локальный путь
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Записываем данные в XML (например, элементы справочника)
ЗаписьXML.ЗаписатьНачалоЭлемента("Данные");
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Контрагент");
ЗаписьXML.ЗаписатьАтрибут("Код", Выборка.Код);
ЗаписьXML.ЗаписатьАтрибут("Наименование", Выборка.Наименование);
ЗаписьXML.ЗаписатьКонецЭлемента(); // Контрагент
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Данные
ЗаписьXML.Закрыть();
// Передача файла на FTP-сервер
FTPСоединение = Новый FTPСоединение("ftp.example.com", , "user", "password");
FTPСоединение.УстановитьТекущийКаталог("/uploads");
FTPСоединение.Загрузить("C:\Temp\ДанныеДляОбмена.xml", "ДанныеДляОбмена.xml");
База-приемник:
// Скачивание файла с FTP-сервера
FTPСоединение = Новый FTPСоединение("ftp.example.com", , "user", "password");
FTPСоединение.УстановитьТекущийКаталог("/uploads");
FTPСоединение.Загрузить("ДанныеДляОбмена.xml", "C:\Temp\ДанныеДляОбмена.xml"); // Локальный путь
// Чтение XML-файла
ЧтениеXML = Новый XMLЧтение();
ЧтениеXML.УстановитьИмяФайла("C:\Temp\ДанныеДляОбмена.xml");
Пока ЧтениеXML.Прочитать() Ци
Если ЧтениеXML.Имя = "Контрагент" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Код = ЧтениеXML.ПолучитьАтрибут("Код");
Наименование = ЧтениеXML.ПолучитьАтрибут("Наименование");
// Поиск или создание контрагента в базе-приемнике
КонтрагентОбъект = Справочники.Контрагенты.НайтиПоКоду(Код);
Если КонтрагентОбъект = Неопределено Тогда
КонтрагентОбъект = Справочники.Контрагенты.СоздатьЭлемент();
КонтрагентОбъект.Код = Код;
Иначе
КонтрагентОбъект = КонтрагентОбъект.ПолучитьОбъект();
КонецЕсли;
КонтрагентОбъект.Наименование = Наименование;
КонтрагентОбъект.Записать();
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Web-сервисы представляют собой технологию для обмена данными между различными приложениями, написанными на разных языках и расположенными в разных узлах сети. Они обеспечивают удаленный вызов процедур, что позволяет обмениваться данными в режиме реального времени.
В 1С Web-сервисы реализуются на основе механизма XDTO (XML Data Transfer Objects). XDTO позволяет нам описывать структуру XML-файлов для входящих и исходящих данных, оперируя прикладными понятиями 1С. Для работы Web-сервисов требуется публикация информационной базы на веб-сервере (например, Apache или IIS).
Определение Web-сервиса в конфигураторе:
Web-сервисы.ПолучитьСписокКонтрагентов, СоздатьЗаявку).XDTO-пакеты).Пример вызова Web-сервиса из 1С:
// URL к WSDL-описанию Web-сервиса
// Например: http://<адрес_сервера>/<имя_публикации>/ws/<имя_сервиса>.1cws?wsdl
АдресWSDL = "http://api.example.com/MyService.1cws?wsdl";
// Создаем объект WSОпределения
Попытка
Определение = Новый WSОпределения(АдресWSDL);
Исключение
Сообщить("Ошибка при получении WSDL: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Создаем прокси Web-сервиса
// ПространствоИменСервиса, ИмяСервиса, ИмяПорта - можно найти в WSDL
ИмяПространстваИмен = "http://www.example.com/MyService";
ИмяСервиса = "MyService";
ИмяПорта = "MyServiceSoap";
Прокси = Новый WSПрокси(Определение, ИмяПространстваИмен, ИмяСервиса, ИмяПорта);
// Вызываем операцию Web-сервиса
// Предположим, у нас есть операция "ПолучитьДанныеКонтрагента" с параметром "Код"
ПараметрКод = "000000001";
Попытка
Результат = Прокси.ПолучитьДанныеКонтрагента(ПараметрКод);
Сообщить("Получены данные: " + Результат.Наименование);
Исключение
Сообщить("Ошибка вызова Web-сервиса: " + ОписаниеОшибки());
КонецПопытки;
HTTP-сервисы являются более современным и гибким подходом по сравнению с Web-сервисами, особенно в контексте REST-архитектуры. Они основаны на "голом" HTTP и позволяют использовать различные форматы передачи данных, включая JSON, XML и простой текст.
В 1С мы создаем HTTP-сервис, определяем его базовый URL и шаблоны URL для различных методов (GET, POST, PUT, DELETE). Для каждого шаблона мы пишем обработчик HTTP-метода на встроенном языке 1С. Эти сервисы также требуют публикации информационной базы на веб-сервере (Apache или IIS).
Определение HTTP-сервиса в конфигураторе:
HTTP-сервисы./api/v1)./documents/orders для работы с заявками.Пример обработчика POST-запроса в 1С:
// В модуле HTTP-сервиса или в общем модуле, который связан с HTTP-сервисом
&НаСервере
Процедура ПринятьЗаявку(Запрос, Ответ)
// Запрос - это объект HTTPСервисЗапрос
// Ответ - это объект HTTPСервисОтвет
Попытка
// Получаем тело запроса как строку
ТекстЗапроса = Запрос.ПолучитьТелоКакСтроку();
// Создаем объект для чтения JSON
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(ТекстЗапроса);
// Читаем данные из JSON
ДанныеЗаявки = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Пример: ДанныеЗаявки могут быть структурой или соответствием
// Например, { "Номер": "З001", "Дата": "2023-10-27", "Контрагент": "Покупатель1" }
Сообщить("Получена заявка: Номер " + ДанныеЗаявки.Номер + ", Дата " + ДанныеЗаявки.Дата);
// Создаем новую заявку в базе-приемнике
НоваяЗаявка = Документы.Заявка.СоздатьДокумент();
НоваяЗаявка.Номер = ДанныеЗаявки.Номер;
НоваяЗаявка.Дата = ДанныеЗаявки.Дата;
// ... заполняем другие реквизиты ...
НоваяЗаявка.Записать();
// Формируем ответ об успешном приеме
РезультатОтвета = Новый Структура("Статус, Сообщение", "OK", "Заявка успешно принята");
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, РезультатОтвета);
Ответ.КодСостояния = 200; // OK
Ответ.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть(), КодировкаТекста.UTF8, "application/json");
Исключение
// В случае ошибки формируем ответ с кодом ошибки
РезультатОтвета = Новый Структура("Статус, Сообщение", "ERROR", ОписаниеОшибки());
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, РезультатОтвета);
Ответ.КодСостояния = 500; // Внутренняя ошибка сервера
Ответ.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть(), КодировкаТекста.UTF8, "application/json");
КонецПопытки;
КонецПроцедуры
OData — это открытый веб-протокол для запроса и обновления данных, который позволяет выполнять операции с ресурсами (такими как элементы справочников или документы) с помощью стандартных HTTP-команд (GET, POST, PUT, DELETE) и получать ответы в форматах XML или JSON.
Платформа 1С, начиная с версии 8.3.5, предоставляет встроенную поддержку доступа к данным через OData. После публикации информационной базы на веб-сервере и активации поддержки OData для необходимых объектов метаданных, 1С автоматически создает REST-интерфейс. Это позволяет нам получать структуру метаданных и сами объекты с установленными фильтрами.
УстановитьСоставСтандартногоИнтерфейсаOData.Включение поддержки OData для объекта метаданных в конфигураторе:
Чтобы предоставить доступ к справочнику Контрагенты через OData, мы должны в модуле менеджера этого справочника вызвать метод:
// В модуле менеджера справочника "Контрагенты"
Процедура УстановитьСоставСтандартногоИнтерфейсаOData() Экспорт
СтандартныеИнтерфейсыOData.УстановитьСоставСтандартногоИнтерфейсаOData(Истина, Метаданные.Справочники.Контрагенты);
КонецПроцедуры
После публикации базы на веб-сервере, мы сможем обращаться к данным контрагентов по URL:
// Пример URL для получения списка контрагентов в JSON-формате
// http://<адрес_сервера>/<имя_публикации>/odata/standard.odata/Catalog_Контрагенты?$format=json
// Пример URL для получения конкретного контрагента по ID
// http://<адрес_сервера>/<имя_публикации>/odata/standard.odata/Catalog_Контрагенты(guid'...')?$format=json
// Пример URL для фильтрации контрагентов по наименованию
// http://<адрес_сервера>/<имя_публикации>/odata/standard.odata/Catalog_Контрагенты?$filter=Description eq 'МойКонтрагент'&$format=json
RabbitMQ — это популярный брокер сообщений, используемый для организации стабильного и масштабируемого асинхронного обмена сообщениями между различными информационными системами. Он устанавливается на отдельный сервер и представляет собой мощный инструмент для обеспечения гарантированной доставки сообщений.
RabbitMQ действует как "транспортная компания" для наших сообщений. Мы отправляем "посылку" (сообщение) в RabbitMQ, который гарантирует ее доставку "другу" (другой базе 1С). Сообщения помещаются в очереди, из которых их могут забирать потребители. RabbitMQ обеспечивает асинхронное взаимодействие, гарантированную доставку и сохранение порядка сообщений.
База-источник (отправка сообщения):
// Предполагаем, что внешняя компонента PinkRabbitMQ уже подключена
// Например: ПодключитьВнешнююКомпоненту("PinkRabbitMQ");
Попытка
// Создаем клиент RabbitMQ и подключаемся к серверу
Клиент = Новый PinkRabbitMQ.Клиент();
Клиент.Подключиться("amqp://guest:guest@localhost:5672/"); // Укажите актуальные параметры
// Подготавливаем данные для отправки (например, структура заявки)
ДанныеЗаявки = Новый Структура("Номер, Дата, Сумма", "З001", ТекущаяДата(), 1500.00);
// Сериализуем данные в JSON-строку для передачи
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеЗаявки);
СтрокаСообщения = ЗаписьJSON.Закрыть();
// Отправляем сообщение в точку обмена с определенным ключом маршрутизации
Клиент.ОтправитьСообщение("ExchangeЗаявки", "RoutingKeyЗаявки", СтрокаСообщения);
Сообщить("Сообщение с заявкой отправлено в RabbitMQ.");
Клиент.Отключиться();
Исключение
Сообщить("Ошибка при отправке сообщения в RabbitMQ: " + ОписаниеОшибки());
КонецПопытки;
База-приемник (получение сообщения):
// Предполагаем, что внешняя компонента PinkRabbitMQ уже подключена
Попытка
// Создаем клиент RabbitMQ и подключаемся к серверу
Клиент = Новый PinkRabbitMQ.Клиент();
Клиент.Подключиться("amqp://guest:guest@localhost:5672/"); // Укажите актуальные параметры
// Получаем сообщение из очереди
// ИмяОчереди должно быть настроено в RabbitMQ и связано с ExchangeЗаявки
Сообщение = Клиент.ПолучитьСообщение("QueueЗаявки");
Если Сообщение.ЕстьСообщения Тогда
// Десериализуем данные из JSON-строки
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(Сообщение.ТелоСообщения);
ДанныеЗаявки = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
Сообщить("Получено сообщение с заявкой: Номер " + ДанныеЗаявки.Номер + ", Сумма " + ДанныеЗаявки.Сумма);
// Здесь мы обрабатываем полученные данные, например, создаем документ "Заявка"
НоваяЗаявка = Документы.Заявка.СоздатьДокумент();
НоваяЗаявка.Номер = ДанныеЗаявки.Номер;
НоваяЗаявка.Дата = ДанныеЗаявки.Дата;
НоваяЗаявка.Сумма = ДанныеЗаявки.Сумма;
// ... другие поля ...
НоваяЗаявка.Записать();
Сообщить("Документ Заявка создан.");
// Подтверждаем RabbitMQ, что сообщение успешно обработано и может быть удалено из очереди
Клиент.ПодтвердитьСообщение(Сообщение.DeliveryTag);
Иначе
Сообщить("В очереди QueueЗаявки нет новых сообщений.");
КонецЕсли;
Клиент.Отключиться();
Исключение
Сообщить("Ошибка при получении или обработке сообщения из RabbitMQ: " + ОписаниеОшибки());
КонецПопытки;
Исходя из нашей задачи — обмениваться парой справочников и заявок, пару раз в день, и все это мы будем программировать сами — давайте подведем итоги:
Вне зависимости от выбранной технологии, если обмен происходит через интернет, мы обязаны уделить пристальное внимание вопросам безопасности:
HttpOnly, Secure, SameSite и других механизмов.Для нашей задачи с обменом "пары справочников и заявок пару раз в день" при самостоятельном программировании, HTTP-сервисы представляют собой наиболее оптимальный и современный выбор. Они обеспечивают достаточную гибкость, производительность и удобство разработки при адекватном уровне контроля над безопасностью. При этом, если требуется максимально простая реализация и есть возможность обеспечить безопасность канала, то XML через FTP также может быть рассмотрен. Каждый из методов имеет свои сценарии использования, и наш выбор должен быть обусловлен тщательным анализом всех требований и возможностей.