При интеграции 1С со сторонними веб-сервисами и сайтами (особенно разработанными на платформе Microsoft .NET / C#) часто возникает требование передавать уникальные идентификаторы не обычной строкой вида 08ed0482-a722-4182-b410-e77f3acc34e6, а в виде массива из 16 байт, закодированного в строку Base64.
Если выполнить прямое преобразование шестнадцатеричной строки в двоичные данные, принимающая сторона может не распознать переданный идентификатор. Разберем причины такого поведения и рассмотрим готовые варианты решения задачи.
Выясним, почему простое удаление дефисов и преобразование в Base64 не дает ожидаемого внешней системой результата. Стандартный GUID представляет собой 128-битное число (16 байт). Однако формат его сериализации в массив байтов различается:
Guid.ToByteArray() в .NET первые три компонента структуры записываются в порядке Little-Endian (от младшего байта к старшему), а оставшиеся две — в порядке Big-Endian:
Для того чтобы внешняя система на базе .NET смогла корректно прочитать GUID из строки Base64, нам необходимо выполнить аналогичную перестановку байтов на стороне 1С.
Начиная с версии платформы 1С:Предприятие 8.3.10, доступны объекты БуферДвоичныхДанных и методы ПолучитьБуферДвоичныхДанныхИзHexСтроки, ПолучитьBase64СтрокуИзБуфераДвоичныхДанных. Это позволяет выполнить операцию исключительно средствами встроенного языка без создания временных файлов и внешних библиотек.
Разберем по шагам алгоритм преобразования:
БуферДвоичныхДанных из шестнадцатеричной строки.Посмотрим на программный код функции:
Функция ГУИД_Из_1С_в_Base64(ГУИД_Из_1С_Строкой) Экспорт
// Очищаем строку GUID от дефисов
ГУИДБезДефисов = СтрЗаменить(ГУИД_Из_1С_Строкой, "-", "");
// Получаем двоичный буфер из Hex-строки
БуферДанных = ПолучитьБуферДвоичныхДанныхИзHexСтроки(ГУИДБезДефисов);
// Формируем карту перестановки байтов (индексы от 1)
КартаИнверсии = Новый Соответствие;
КартаИнверсии.Вставить(4, 1);
КартаИнверсии.Вставить(3, 2);
КартаИнверсии.Вставить(6, 5);
КартаИнверсии.Вставить(8, 7);
// Инвертируем байты в первых трех сегментах
Для Каждого КлючИнверсии Из КартаИнверсии Цикл
ЗначениеПриемника = БуферДанных.Получить(КлючИнверсии.Значение - 1);
ЗначениеИсточника = БуферДанных.Получить(КлючИнверсии.Ключ - 1);
БуферДанных.Установить(КлючИнверсии.Ключ - 1, ЗначениеПриемника);
БуферДанных.Установить(КлючИнверсии.Значение - 1, ЗначениеИсточника);
КонецЦикла;
// Кодируем полученный буфер в Base64
Возврат ПолучитьBase64СтрокуИзБуфераДвоичныхДанных(БуферДанных);
КонецФункции
Если веб-сервис присылает ответ с идентификатором в формате Base64, нам потребуется выполнить обратную операцию для поиска или записи ссылки в базе 1С. Проанализируем реализацию обратной функции:
Функция ГУИД_Из_Base64_В_1С(ГУИД_Base64_Строкой) Экспорт
// Декодируем Base64 в буфер двоичных данных
БуферДанных = ПолучитьБуферДвоичныхДанныхИзBase64Строки(ГУИД_Base64_Строкой);
// Карта перестановки байтов для возврата в Big-Endian
КартаИнверсии = Новый Соответствие;
КартаИнверсии.Вставить(4, 1);
КартаИнверсии.Вставить(3, 2);
КартаИнверсии.Вставить(6, 5);
КартаИнверсии.Вставить(8, 7);
Для Каждого КлючИнверсии Из КартаИнверсии Цикл
ЗначениеПриемника = БуферДанных.Получить(КлючИнверсии.Ключ - 1);
ЗначениеИсточника = БуферДанных.Получить(КлючИнверсии.Значение - 1);
БуферДанных.Установить(КлючИнверсии.Ключ - 1, ЗначениеИсточника);
БуферДанных.Установить(КлючИнверсии.Значение - 1, ЗначениеПриемника);
КонецЦикла;
// Получаем hex-строку и форматируем ее дефисами
HexСтрока = ПолучитьHexСтрокуИзБуфераДвоичныхДанных(БуферДанных);
Результат = Сред(HexСтрока, 1, 8) + "-"
+ Сред(HexСтрока, 9, 4) + "-"
+ Сред(HexСтрока, 13, 4) + "-"
+ Сред(HexСтрока, 17, 4) + "-"
+ Сред(HexСтрока, 21);
Возврат Новый УникальныйИдентификатор(НРег(Результат));
КонецФункции
Рассмотрим альтернативный вариант, который можно применить, если на сервере или клиенте 1С зарегистрирована специальная COM-обертка для вызова методов .NET CLR. В этом случае задача решается прямым вызовом нативных методов System.Guid.Parse и System.Convert.ToBase64String:
// Пример вызова через зарегистрированный COM-мост
NetObject = Новый COMОбъект("NetObjectToIDispatch45");
ТипGuid = NetObject.ПолучитьТип("System.Guid");
ТипConvert = NetObject.ПолучитьТип("System.Convert");
ОбъектGuid = ТипGuid.Parse("08ed0482-a722-4182-b410-e77f3acc34e6");
МассивБайт = ОбъектGuid.ToByteArray();
ИтоговыйGUID = ТипConvert.ToBase64String(МассивБайт);
// Результат: "ggTtCCKngkG0EOd/Osw05g=="
При передаче идентификаторов через параметры URL в REST API принимающая сторона может ожидать строку в формате URL-Safe Base64 (без спецсимволов +, / и знаков выравнивания =). В таком случае после выполнения стандартной функции достаточно выполнить простую строковую замену:
Base64Url = СтрЗаменить(СтрЗаменить(Base64Строка, "+", "-"), "/", "_");
Base64Url = СтрЗаменить(Base64Url, "=", "");