При интеграции 1С со сторонними веб-сервисами, особенно написанными на PHP, Python или JavaScript, разработчики часто сталкиваются с путаницей в терминологии типов данных. Одной из распространенных проблем является формирование правильной структуры JSON для полезной нагрузки (payload) при отправке запросов, например, при генерации JWT-токенов.
В этой статье мы подробно разберем ситуацию, когда сторонний сервер ожидает получить «двухуровневый массив» или ассоциативный массив, а 1С при стандартной сериализации выдает некорректный формат. Мы выясним, почему возникает ошибка, разберем различия в типах данных между 1С и JSON, и научимся правильно формировать вложенные объекты.
Рассмотрим типичную задачу. Нам необходимо отправить POST-запрос на сервер, передав JWT-токен. В полезной нагрузке этого токена должен содержаться параметр cnt, внутри которого находятся данные, например, ИНН. Сторонние разработчики (часто пишущие на PHP) могут сформулировать требование как необходимость передать «двухуровневый массив»:
[cnt] => Array (
[inn] => 123456789
)
Если попытаться реализовать это в 1С буквально, используя тип данных Массив, и затем сериализовать это в JSON, мы получим следующий результат:
// Неверный результат сериализации массива 1С
"cnt": [
{
"inn": "123456789"
}
]
Обратите внимание на квадратные скобки []. В синтаксисе JSON они обозначают список (массив). Сервер, получая такой пакет, не может обратиться к полю по имени ключа напрямую (например, payload.cnt.inn), так как cnt является списком, и ему нужно обращаться по индексу (например, payload.cnt[0].inn). В результате сервер возвращает ошибку валидации данных, например: "The INN is bad".
Чтобы решить проблему, нужно понимать, как механизмы сериализации (например, объект ЗаписьJSON) преобразуют типы 1С в формат JSON. Давайте проанализируем основные соответствия:
В 1С это коллекция индексированных значений. В JSON это значения в квадратных скобках [...]. Используется, когда порядок элементов важен, а ключи (имена) элементов не нужны.
В 1С это коллекция пар "Ключ-Значение", где ключ — строка. В JSON это значения в фигурных скобках {...}. Это аналог "Ассоциативного массива" в PHP или "Словаря" (Dictionary) в других языках. Именно этот тип нужен, когда сторонний API требует передачу параметров по именам.
Также преобразуется в объект {}, если ключами являются строки. Однако порядок полей при сериализации Соответствия не всегда гарантирован (хотя в стандарте JSON порядок ключей в объекте и не должен иметь значения, некоторые парсеры могут быть к этому чувствительны).
Важное замечание про PHP: В языке PHP термин "Array" (массив) используется и для обычных списков ['a', 'b'], и для ассоциативных массивов ['key' => 'value']. Поэтому, когда PHP-разработчик просит отправить "массив", он часто имеет в виду JSON-объект (Structure в терминах 1С).
Теперь, когда мы выяснили разницу, перейдем к правильной реализации. Нам нужно получить JSON следующего вида:
{
"cnt": {
"inn": "123456789"
}
}
Здесь мы видим вложенность: объект внутри объекта (фигурные скобки внутри фигурных скобок). В терминах 1С это означает, что нам нужно создать одну Структуру и поместить ее как значение внутрь другой Структуры.
Давайте рассмотрим пошаговый алгоритм написания кода в 1С.
Сначала создадим ту часть данных, которая находится на самом глубоком уровне вложенности. В нашем случае это данные с ИНН.
// Создаем структуру для внутренних данных
ДанныеИНН = Новый Структура;
ДанныеИНН.Вставить("inn", "123456789");
Теперь создадим корневую структуру и поместим в неё наши ДанныеИНН под ключом cnt.
// Создаем корневую структуру
Payload = Новый Структура;
// Вставляем структуру в структуру
Payload.Вставить("cnt", ДанныеИНН);
// Добавим другие обязательные поля токена, если нужно
Payload.Вставить("iat", ТекущаяУниверсальнаяДатаВМиллисекундах());
// ... и так далее
Для преобразования полученной структуры 1С в строку JSON используем объект ЗаписьJSON. Это наиболее надежный способ, который гарантирует правильную расстановку скобок и кавычек.
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
// Записываем нашу структуру
ЗаписатьJSON(ЗаписьJSON, Payload);
// Получаем готовую строку
СтрокаJSON = ЗаписьJSON.Закрыть();
В результате переменная СтрокаJSON будет содержать именно то, что ожидает сервер:
{"cnt":{"inn":"123456789"},"iat":...}
Давайте проанализируем ошибку, которую допускал автор вопроса изначально. Код выглядел примерно так:
// ОШИБОЧНЫЙ ВАРИАНТ
ВложенныйМассив = Новый Массив;
СтруктураСИнн = Новый Структура("inn", "123456789");
ВложенныйМассив.Добавить(СтруктураСИнн);
Payload = Новый Структура;
Payload.Вставить("cnt", ВложенныйМассив);
При сериализации такого кода 1С видит тип Массив и честно оборачивает его в квадратные скобки []. Получается JSON:
{"cnt": [{"inn": "123456789"}]}
Сервер на PHP, получая такой запрос, пытается выполнить код вроде $data['cnt']['inn']. Но так как cnt теперь массив (список), у него нет ключа inn, у него есть только индекс 0. Ключ inn находится внутри элемента с индексом 0. Поэтому проверка на сервере падает с ошибкой, утверждая, что ИНН не найден или некорректен.
При работе с JSON в 1С стоит учитывать еще несколько важных моментов, чтобы избежать подобных проблем в будущем:
ЗаписьJSON.Закрыть()) и проверьте её в любом онлайн-валидаторе JSON. Обращайте внимание на типы скобок: {} — это объект, [] — это массив.{ "key": "value" }, в 1С всегда используйте Структура. Для отладки и эмуляции запросов удобно применять аналог Postman на платформе 1С.[ "value1", "value2" ], в 1С используйте Массив.СериализаторXDTO. Он мощнее, но по умолчанию может добавлять в JSON служебные поля (например, #type), специфичные для платформы 1С. Сторонние системы их не поймут. Если используете XDTO, убедитесь, что настройки сериализации отключены для вывода информации о типах, либо используйте "чистую" запись через ЗаписьJSON.Таким образом, для решения задачи "двухуровневого ассоциативного массива" (в терминологии PHP) в 1С необходимо использовать вложенные структуры. Это обеспечит корректную генерацию JSON-объектов и успешную валидацию данных на принимающей стороне.