Привет читатель хочу поделиться своим недавним опытом интеграции двух различных систем.
Возникла задача о передаче данных между 1С (разработка и настройка была отдана на аутсорсинг), которую планируется использовать как основную систему электронного документооборота (ЭДО) и B2B системой (внутренняя разработка), которая написана на PHP (Symfony) и выполняет функции первичного ввода информации в компании.
У меня уже был опыт интеграции B2B с другой B2B. Суть заключалась к передаче JSONа при помощи cURL. Затем возникла задача интеграции системы «Borlas», основанная на Oracle, где также был применен данный подход. На стороне Oracle, правда, использовался свой пакет — аналог cURL в PHP (если будет интересно, могу описать в новой статье).
Как я выяснил, 1С 8.2 тоже умеет посылать GET и POST запросы. Предположил, что если уже все настроено и работает с другими системами, значит, и тут должно сработать. JSON отвергли разработчики 1С, сказав, что формат неподходящий и они признают только XML. Комментарии о том, что это нам даст минимум в размере при передаче данных, а данных действительно получалось очень много, были отвергнуты. В итоге приступили в подготовке 2 систем на основе XML.
Cо своей стороны я написал приемщик запросов из 1С и возврат результатов. Функция по приему переменной в POST, в которой 1Сники должны были подставлять XML.
Формат примерно следующий:
<xml version="1.0">
<KEY>123ABC456</KEY> //ключ авторизации
<MODE>get_last_orders </MODE> //операцию что хотят выполнить
<LIMIT>4000</LIMIT>//лимит записей что хотят отобрать
</xml>
обработчик, который возвращает уже отобранные по условиям записи и формирует XML вида:
<?xml version="1.0" encoding="utf-8" ?>
<data>
<order>
<type1>1</type1>
<type>OPS</type>
<ref></ref>
<id_doc>4853352</id_doc>
<start_date>01.01.2013</start_date>
<validity>1</validity>
<description>Загружено из b2b</description>
<additional>
<Param>
<ParamName>СНИЛС</ParamName>
<ParamValue>999999999</ParamValue>
</Param>
<Param>
<ParamName>ФИО клиента</ParamName>
<ParamValue>МИХАЙЛОВ МИХАИЛ ЕВГЕНЬЕВИЧ</ParamValue>
</Param>
<Param>
<ParamName>Дата заявления</ParamName>
<ParamValue>01.01.2013</ParamValue>
</Param>
</additional>
</order>
<order>
...
</order>
</data>
Данные могут быть переданные только через HTTPS соединение.
На первый взгляд, кажется, что все просто, но в процессе возникло несколько проблем:
1) аутсорсеры сообщили, что малознакомы с запросами такого рода, и попытались предложить старую проверенную схему:
1. импорт файла из B2B,
2. Загрузка в 1С,
3. Экспорт файла с указанием, что смогли обработать, что нет из 1С,
4. Импорт в Б2Б,
5. и с самого начала…
Схему отвергли, так как нужно быстро, и без участия человека и всяких «кнопочек».
Тогда попросили пример кода. В интернете я «нагуглил» следующий пример:
Сервер = "test.com";
Порт = "443";
Попытка
НТТР = Новый HTTPСоединение(Сервер, Порт, , , , Истина);
Иначе
НТТР = Новый HTTPСоединение(Сервер, Порт);
КонецЕсли;
АдресСкрипта = "/gateway/GetData1C/";
Попытка
НТТР.ОтправитьДляОбработки(ИмяФайлаОтправки, АдресСкрипта, ИмяФайлаОтвета, ЗаголовокHTTP);
Исключение
Сообщить("Неудачная попытка соединения: " + ОписаниеОшибки());
Иначе
ЗаписьЖурналаРегистрации("HTTPСоединение", УровеньЖурналаРегистрации.Ошибка, , , "Неудачная попытка соединения: " + ОписаниеОшибки());
КонецЕсли
Возврат;
КонецПопытки;
На сервер стали приходить данные, но пустые, то есть GET и POST были пустые. Я добавил запись что приходит в логи и успешно забыл об этом. Спустя 4 месяца мне была поставлена срочная задача — довести интеграцию до результата (так как прошло много времени, разработчики 1С работают, работают, но в ответ ничего не приходит). Мне поставили 1С и я начал «ковыряться».
Первое — решил поставить Fiddler, чтобы понять что происходит. Заметил, что соединение идет по HTTP, а затем сервер редиректит на HTTPS. Предположил, что по этой причине данные получаются пустыми. Попробовал в Chrome воспроизвести, и получил подтверждение, что данные в POST запросе теряются при редиректе.
Так как разрешать работу по HTTP нельзя, начал изучать почему, ведь указано, что:
НТТР = Новый HTTPСоединение(Сервер, Порт, , , , Истина);
Параметр «Истина» означает что использовать HTTPS, и тут дошло что срабатывает
НТТР = Новый HTTPСоединение(Сервер, Порт);
В итоге это «Иначе» было выкинуто, и получил ошибку, что некорректный сертификат. Сертификат был само подписной. Разработка интеграции велась на внутренних серверах, где официально купленного сертификата от «Thawte SSL CA» в отличии от PROD сервера. Импорт сертификата во все возможные хранилища не привел к результату.
Поиск по ресурсам привел к тому, что все сертификаты корневые у 1С свои, и на основе них она уже проверяет остальные. Они лежат в тестовом виде в файле «cacert.pem», который расположен в папке «bin», где стоит 1С. Импорт, не так прост, как оказалось.
Для начала надо экспортировать нужный нам сертификат в файл (он у меня уже был в личном хранилище). Запустив «certmgr.msc», найдя сертификат, делаем его экспорт в файл *.cer.
Далее качаем программку Win32OpenSSL и преобразовываем его в тестовый вид.
У меня это получилось так:
C:OpenSSL-Win64bin>openssl x509 -inform der -in С:fiddler.cer -out С:fiddler.pem -text -fingerprint -md5
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
MD5 Fingerprint=13:BF:73:43:BB:69:19:BA:22:5D:C7:2E:44:85:91:7F
MD5 сохраняем, он нам понадобится.
Далее открываем файл «cacert.pem».
Спускаемся в самый низ и добавляем сперва MD5, а потом все содержимое, что получилось в файле «fiddler.pem».
Сохраняем файл.
Перезапускаем 1С (возможно и не надо, но у меня не заработало, поэтому я перезапустил все.
Исходный файл в 1С был приведен в такой вид:
Процедура ПослатьЗапросНажатие(Элемент)
Соединение = ПолучитьHTTPСоединение();
Если Соединение = Неопределено Тогда
Сообщить("Не удалось подключиться к серверу, указанному в настройке обмена! Обработка прервана!");
Иначе
Источник = АдресФайла;
КонецЕсли;
ИмяФайла = ФайлРезультат;
ИмяПостФайла = ПостФайл;
ФайлОтправки = Новый Файл(ИмяПостФайла);
РазмерФайлаОтправки = XMLСтрока(ФайлОтправки.Размер());
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
Заголовки.Вставить("Content-Lenght", РазмерФайлаОтправки);
Попытка
Соединение.ОтправитьДляОбработки(ИмяПостФайла, Источник, ИмяФайла, Заголовки);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки
КонецПроцедуры
Функция ПолучитьHTTPСоединение() Экспорт
Попытка
Соединение = Новый HTTPСоединение(HTTPСервер,"443",,,,Истина);
Исключение
Сообщить(ОписаниеОшибки());
Соединение = Неопределено;
КонецПопытки;
Возврат Соединение;
КонецФункции
Процедура ПриОткрытии()
HTTPСервер = "test.com";
АдресФайла = "/gateway/GetData1C";
ПостФайл = "C:POST_1Cpost.txt";
ФайлРезультат = "C:POST_1Cresult.xml";
КонецПроцедуры
После нажатия на кнопку, пошел запрос по HTTPS и на выходе был получен корректный XML.
Искал, как работает 1С по HTTPS, достаточно много материала, но вот как работать по само подписному сертификату не нашел.
Готов поделиться информацией о злоключениях с настройкой Oracle и B2B.
Там использовался тот же механизм, передача данных в POST запросе, но были свои подводные камни. В принципе, там оказалось все проще.
Автор: ASKEL