Почему ФабрикаXDTO.ПрочитатьJSON() работает на клиенте, но выдает ошибку на сервере 1С при чтении JSON-ответа?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой Управленческий учет Торговля и дистрибуция
← К списку

При интеграции 1С с внешними сервисами, использующими REST API и формат JSON, мы часто сталкиваемся с необходимостью десериализации данных. Для этого в 1С удобно использовать объект ФабрикаXDTO. Однако иногда возникает загадочная ситуация, когда один и тот же код, успешно работающий на клиенте, внезапно начинает выдавать ошибку на сервере. Давайте вместе разберем эту проблему и найдем ее решение.

Разбираем проблему: клиент работает, сервер выдает ошибку

Представим типовой сценарий: выгрузка товаров в ОЗОН через Яндекс Диск, где используется API. Все работало исправно в течение нескольких месяцев, но в один прекрасный день серверная часть перестала обрабатывать ответы от Яндекс Диска, выдавая ошибку. Клиентская же часть при этом продолжает работать без проблем, используя те же самые данные и методы.

Посмотрим на пример кода, который демонстрирует это поведение:


&НаСервере
Процедура ЖСОНСервер()
    // ТУТ НЕ РАБОТАЕТ
    ЧтениеJSON = Новый ЧтениеJSON();
    ЧтениеJSON.УстановитьСтроку(Объект.ТекстОбъекта);
    ТипОбъекта = ФабрикаXDTO.Тип("cloud-api.yandex.net/v1/disk", "uploadGetResponse");
    __Объект = ФабрикаXDTO.ПрочитатьJSON(ЧтениеJSON, ТипОбъекта); 
КонецПроцедуры
    
&НаКлиенте
Процедура жосн(Команда)
    //////////////// ТУТ РАБОТАЕТ ///////////////////
    ЧтениеJSON = Новый ЧтениеJSON();
    ЧтениеJSON.УстановитьСтроку(Объект.ТекстОбъекта);
    ТипОбъекта = ФабрикаXDTO.Тип("cloud-api.yandex.net/v1/disk", "uploadGetResponse");
    __Объект = ФабрикаXDTO.ПрочитатьJSON(ЧтениеJSON, ТипОбъекта); 
        
    ЖСОНСервер();
КонецПроцедуры

В данном примере Объект.ТекстОбъекта содержит JSON-строку, полученную от Яндекс Диска, например, такую:

{"method":"PUT","href":"https://uploader99klg.disk.yandex.net:443/upload-target/20250530T105738.233.utd.16xmn5oe82whiuqfx3aalxwei-k99klg.4087635","templated":false ,"operation_id":"e6edb64271e173f178264c2fdf0d9eb7f08e92fbec09156d4e2a811b33607e7a"}

При вызове метода ФабрикаXDTO.ПрочитатьJSON() на сервере мы получаем следующую ошибку:


Ошибка при вызове метода контекста (ПрочитатьJSON)
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(18)}:__Объект = ФабрикаXDTO.ПрочитатьJSON(ЧтениеJSON, ТипОбъекта);
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(33)}:ЖСОНСервер();
[ОшибкаВоВремяВыполненияВстроенногоЯзыка]
по причине:Ошибка преобразования данных XDTO:
Чтение объекта типа: {cloud-api.yandex.net/v1/disk}uploadGetResponse
Проверка свойства 'method':
    форма: Элемент
    имя: {cloud-api.yandex.net/v1/disk}method
    тип: {http://www.w3.org/2001/XMLSchema}string
по причине:Ошибка проверки данных XDTO:
Структура объекта не соответствует типу: {cloud-api.yandex.net/v1/disk}uploadGetResponse
Проверка свойства 'method':
    форма: Элемент
    имя: {cloud-api.yandex.net/v1/disk}method
    тип: {http://www.w3.org/2001/XMLSchema}string
Не установлено значение одного из следующих свойств: operation_id

Ошибка явно указывает на проблему с валидацией данных XDTO и упоминает, что "Не установлено значение одного из следующих свойств: operation_id", хотя в приходящей JSON-строке это свойство присутствует.

Разбираем причину: строгая валидация сервера и XDTO-схемы

Чтобы выяснить причину такого поведения, нам необходимо проанализировать несколько ключевых моментов:

  1. Различия в поведении ФабрикиXDTO на клиенте и сервере. Это известная особенность платформы 1С: серверный контекст, как правило, применяет более строгую валидацию данных по XDTO-схеме, чем клиентский. Клиентская часть может быть более "прощающей" к незначительным отклонениям от схемы, тогда как сервер требует точного соответствия.
  2. XDTO-схема для типа uploadGetResponse. Давайте посмотрим на определение этого типа в XDTO-пакете, который был импортирован из XSD-схемы Яндекс Диска:


    
        
        
        
        
    

Обратите внимание на тег <xs:sequence>. Этот тег в XSD-схемах означает, что порядок следования элементов должен быть строго соблюден. То есть, 1С, основываясь на этой схеме, ожидает, что поля в JSON-ответе будут идти именно в таком порядке: сначала operation_id, затем href, method и templated.

  1. Сравнение XDTO-схемы с реальным JSON-ответом.
    • Ожидаемый порядок (из XSD): operation_id, href, method, templated.
    • Фактический порядок (из JSON-строки): method, href, templated, operation_id.
    Мы видим, что порядок полей в JSON-ответе от Яндекс Диска не соответствует порядку, определенному в XDTO-схеме. В частности, поле method идет первым, тогда как схема ожидает operation_id.

Почему же возникает ошибка "Не установлено значение одного из следующих свойств: operation_id"? Серверный парсер ФабрикаXDTO, работая в строгом режиме и видя <xs:sequence> в схеме, ожидает найти operation_id на первой позиции. Когда он обнаруживает там method, он расценивает это как несоответствие и считает, что operation_id "не установлено" в ожидаемой позиции, даже если оно присутствует дальше в JSON-строке.

Как оказалось, внешние API, такие как Яндекс Диск, могут менять порядок полей в JSON-ответах, поскольку стандарт JSON (RFC 7159) определяет объекты как неупорядоченные коллекции пар "имя/значение". Это означает, что порядок полей в JSON-объекте не гарантируется и может изменяться.

Решение проблемы: свойство "Упорядоченный" в XDTO-пакете

Ключевым моментом для решения этой проблемы является изменение одного свойства в определении типа uploadGetResponse в вашем XDTO-пакете. Нам необходимо установить свойство "Упорядоченный" (Ordered) в значение Ложь.

Давайте разберем по шагам, как это сделать:

  1. Откройте конфигуратор 1С.
  2. Перейдите в раздел Общие, затем выберите XDTO-пакеты.
  3. Найдите нужный XDTO-пакет, соответствующий пространству имен вашего сервиса (в нашем случае это cloud-api.yandex.net/v1/disk).
  4. В дереве объектов XDTO-пакета разверните его и найдите тип uploadGetResponse.
  5. Выделите тип uploadGetResponse и в окне свойств этого типа (обычно внизу или справа) найдите свойство Упорядоченный.
  6. Установите значение этого свойства в Ложь.

После сохранения изменений и обновления конфигурации базы данных, ваш серверный код с ФабрикаXDTO.ПрочитатьJSON() должен начать работать корректно.

Подробнее о свойстве "Упорядоченный" и работе с JSON

Давайте рассмотрим подробнее, как работает свойство Упорядоченный и почему его изменение решает нашу проблему:

Важно помнить, что стандарт JSON определяет объекты как неупорядоченные коллекции. Внешние API могут возвращать поля в JSON-объектах в произвольном порядке, и этот порядок может меняться со временем без предупреждения. Если ваша XDTO-схема в 1С ожидает строгий порядок, это может привести к внезапным ошибкам при десериализации.

Наши рекомендации для устойчивой интеграции с внешними API

Проанализировав эту ситуацию, мы можем сформулировать несколько рекомендаций для более надежной работы с внешними REST API в 1С:

  1. Всегда проверяйте изменчивость порядка полей. При интеграции с новыми внешними API, особенно когда ответы приходят в формате JSON, всегда предполагайте, что порядок полей в объектах может быть переменным.
  2. Используйте Упорядоченный = Ложь для JSON-объектов. Для типов объектов XDTO, которые соответствуют JSON-объектам и могут иметь переменный порядок полей, рекомендуется устанавливать свойство Упорядоченный в Ложь в XDTO-пакете. Это значительно повысит устойчивость вашей интеграции к изменениям порядка полей во внешних системах.
  3. Помните об особенностях ФабрикаXDTO. Механизм XDTO в 1С, изначально разработанный для XML, был адаптирован для работы с JSON, но имеет свои нюансы в валидации и интерпретации схем. Понимание этих особенностей поможет вам избежать подобных проблем в будущем.

Таким образом, мы выяснили, что причиной проблемы является строгая валидация порядка полей в XDTO-схеме на серверной стороне 1С, которая по умолчанию ожидает порядок, определенный тегом <xs:sequence>. Изменив свойство Упорядоченный на Ложь для соответствующего типа XDTO, мы разрешаем парсеру игнорировать порядок полей, что делает интеграцию более гибкой и устойчивой к изменениям во внешних API.

← К списку