Как получить JSON-данные по HTTPS-ссылке в 1С и вывести их в таблицу значений?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешними системами часто возникает необходимость получить данные в формате JSON по HTTP или HTTPS-ссылке. Однако, при работе с защищенным протоколом HTTPS, можно столкнуться с распространенной ошибкой "400 Bad Request", которая указывает на неверную настройку соединения. В этой статье мы подробно разберем, как правильно настроить HTTP-запрос в 1С для работы с HTTPS, обработать полученные JSON-данные и вывести их в таблицу значений на форме, а также рассмотрим типичные ошибки и способы их устранения.

Анализируем начальную проблему и сообщение об ошибке

Предположим, мы хотим получить структуру JSON с внешнего сервера по HTTPS-ссылке, например, https://apps-2.v.ru/test_1c.php. Начальный подход может выглядеть так:


&НаКлиенте
Процедура Загрузить(Команда)
	ВыполнитьЗагрузкуНаСервере();
КонецПроцедуры

// Внимание: для работы с HTTPСоединение в тонком/веб-клиенте требуется &НаСервере
// В данном примере, для упрощения, код пока находится на клиенте, но рекомендуется переносить на сервер.
// &НаКлиенте или &НаСервере, в зависимости от контекста приложения
Процедура ВыполнитьЗагрузкуНаСервере()
	HTTPСоединение = Новый HTTPСоединение("https://apps-2.v.ru ,); // Обратите внимание на лишнюю запятую и отсутствие порта
	HTTPЗапрос	 = Новый HTTPЗапрос("/test_1c.php"); 
	HTTPЗапрос.Заголовки.Вставить("Content-type", "application/json");	
	
	Запрос	= HTTPСоединение.Получить(HTTPЗапрос); // Здесь возникает ошибка
	Результат = ЧтениеJSON(Запрос.ПолучитьТелоКакСтроку());
КонецПроцедуры

При попытке выполнить такой запрос, мы можем получить ошибку на строке Запрос = HTTPСоединение.Получить(HTTPЗапрос);. После корректировки синтаксиса (убрав лишнюю запятую в конструкторе HTTPСоединение), следующей распространенной ошибкой будет "400 Bad Request" (Ошибочный запрос) с подробным описанием:




400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.

А затем, если мы пытаемся прочитать этот HTML-текст как JSON, получаем ошибку: "Непредвиденный символ при чтении JSON".

Что означает эта ошибка? Сообщение "You're speaking plain HTTP to an an SSL-enabled server port. Instead use the HTTPS scheme to access this URL, please." (Вы обращаетесь по обычному HTTP к порту сервера с поддержкой SSL. Вместо этого используйте схему HTTPS для доступа к этому URL, пожалуйста.) прямо указывает на причину: мы пытаемся установить незащищенное HTTP-соединение с сервером, который ожидает защищенное HTTPS-соединение. Даже если в строке мы указали "https://", объект HTTPСоединение по умолчанию не использует SSL/TLS шифрование, если ему явно не указать это.

Вторая ошибка "Непредвиденный символ при чтении JSON" возникает потому, что вместо ожидаемого JSON-ответа сервер прислал нам HTML-страницу с описанием ошибки "400 Bad Request". Функция ЧтениеJSON(), естественно, не может разобрать HTML как JSON.

Основа решения: ЗащищенноеСоединениеOpenSSL

Для корректной работы с HTTPS-запросами в 1С необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Этот объект является обязательным параметром в конструкторе HTTPСоединение, когда мы взаимодействуем с серверами по протоколу HTTPS.

Разберем параметры конструктора HTTPСоединение и ЗащищенноеСоединениеOpenSSL подробнее:

  1. Новый HTTPСоединение(ИмяСервера, Порт, Пользователь, Пароль, Таймаут, ФлагЗаписиПротокола, ЗащищенноеСоединение, ДополнительныеЗаголовки)
    • ИмяСервера: Имя или IP-адрес сервера (например, "apps-2.v.ru"). Важно: не включайте "https://" сюда. Это указывается через параметр ЗащищенноеСоединение.
    • Порт: Для HTTPS это обычно 443.
    • Пользователь, Пароль: Если требуется HTTP-аутентификация (Basic или Digest). В данном случае, судя по примеру, это "admin" и "1234".
    • Таймаут: Время ожидания ответа от сервера в секундах. По умолчанию может быть небольшим, для медленных серверов рекомендуется увеличить.
    • ЗащищенноеСоединение: Вот здесь мы и передаем объект ЗащищенноеСоединениеOpenSSL().
  2. Новый ЗащищенноеСоединениеOpenSSL(СертификатКлиента, ПарольСертификата, ПутьККорневымСертификатам, ПроверятьСервер)
    • СертификатКлиента: Объект СертификатМенеджер, если сервер требует клиентский сертификат для аутентификации. В большинстве случаев не используется.
    • ПарольСертификата: Пароль к клиентскому сертификату.
    • ПутьККорневымСертификатам: Путь к файлу или каталогу, содержащему корневые сертификаты, если сервер использует самоподписанные или корпоративные сертификаты, не доверенные ОС. В большинстве случаев, если сервер использует стандартные доверенные сертификаты, этот параметр можно не указывать, и 1С будет использовать системное хранилище.
    • ПроверятьСервер: Логическое значение. Истина (по умолчанию) - 1С будет проверять подлинность сертификата сервера. Ложь - проверка отключается (не рекомендуется для продуктивных систем из соображений безопасности).

Для большинства стандартных случаев, когда сервер использует доверенные SSL-сертификаты, достаточно создать ЗащищенноеСоединениеOpenSSL без параметров:


Новый ЗащищенноеСоединениеOpenSSL()

Реализуем решение: корректный HTTP-запрос и парсинг JSON

Теперь, когда мы понимаем, как правильно настроить защищенное соединение, давайте применим эти знания и перепишем наш код. Для лучшей практики, операции с внешними HTTP-запросами рекомендуется выполнять на сервере, так как это обеспечивает лучшую безопасность и управляемость, особенно в веб- и тонком клиенте.

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


&НаКлиенте
Процедура Загрузить(Команда)
    ЭтотОбъект.тзДанныеJSON.Очистить(); // Очищаем таблицу значений перед загрузкой
    ВыполнитьЗагрузкуНаСервере();
КонецПроцедуры

Далее, создаем серверную процедуру ВыполнитьЗагрузкуНаСервере(). Здесь мы правильно инициализируем HTTPСоединение с использованием ЗащищенноеСоединениеOpenSSL.


&НаСервере
Процедура ВыполнитьЗагрузкуНаСервере()
    Попытка
        // Имя сервера, порт 443 для HTTPS, пользователь и пароль для аутентификации
        // Использование ЗащищенноеСоединениеOpenSSL для защищенного соединения
        HTTPСоединение = Новый HTTPСоединение("apps-2.v.ru", 443, "admin", "1234",,, Новый ЗащищенноеСоединениеOpenSSL());
        
        HTTPЗапрос   = Новый HTTPЗапрос("/test_1c.php"); 
        HTTPЗапрос.Заголовки.Вставить("Content-type", "application/json");    
        // Если ожидаем ответ в определенной кодировке, можно указать (например, "UTF-8")
        // HTTPЗапрос.Заголовки.Вставить("Accept-Charset", "UTF-8");

        HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);

        Если HTTPОтвет.Статус = 200 Тогда // Проверяем успешность выполнения запроса
            // Получаем тело ответа как строку
            СтрокаJSON = HTTPОтвет.ПолучитьТелоКакСтроку();
            // Вызываем функцию для чтения и парсинга JSON
            ЧтениеJSONВТаблицу(СтрокаJSON);
        Иначе
            СообщениеОбОшибке = "Ошибка HTTP-запроса. Статус: " + HTTPОтвет.Статус + ". Тело ответа: " + HTTPОтвет.ПолучитьТелоКакСтроку();
            Сообщить(СообщениеОбОшибке);
            ЖурналРегистрации.Записать(
                "ОшибкаHTTPЗапроса",
                УровеньЖурнала.Ошибка,
                ,
                ,
                СообщениеОбОшибке
            );
        КонецЕсли;
    Исключение
        Сообщить("Произошла ошибка при выполнении HTTP-запроса: " + ОписаниеОшибки());
        ЖурналРегистрации.Записать(
            "ОшибкаHTTPСоединения",
            УровеньЖурнала.Ошибка,
            ,
            ,
            "Не удалось выполнить HTTP-запрос: " + ОписаниеОшибки()
        );
    КонецПопытки;
КонецПроцедуры

Обратите внимание на несколько ключевых моментов в этом коде:

  1. Мы используем блок Попытка...Исключение для корректной обработки возможных сетевых ошибок или ошибок таймаута.
  2. Мы явно проверяем HTTPОтвет.Статус. Статус 200 означает успешное выполнение запроса. Если статус другой (например, 404, 500, или в нашем случае 400), это указывает на проблему на стороне сервера или запроса. Только после проверки статуса мы приступаем к обработке тела ответа.
  3. HTTPСоединение создается с указанием имени сервера, порта (443), аутентификационных данных и объекта Новый ЗащищенноеСоединениеOpenSSL().
  4. Метод Получить объекта HTTPСоединение возвращает объект HTTPОтвет, из которого мы можем получить статус и тело ответа.

Парсинг JSON и заполнение таблицы значений

После успешного получения строки JSON, нам необходимо ее прочитать и заполнить таблицу значений на форме. Для этого мы создадим отдельную функцию ЧтениеJSONВТаблицу.


&НаСервере
// Функция, которая будет вызываться с сервера для чтения JSON и заполнения таблицы значений на форме
Функция ЧтениеJSONВТаблицу(ДанныеJSON)
    ЧтениеJSONОбъект = Новый ЧтениеJSON;
    ЧтениеJSONОбъект.УстановитьСтроку(ДанныеJSON);         
    
    // ПрочитатьJSON автоматически десериализует JSON в структуру или массив 1С
    СтруктураДанных = ПрочитатьJSON(ЧтениеJSONОбъект, Истина); // Истина - для использования совместимости с JSON RFC 4627

    // Проверяем, соответствует ли структура JSON нашим ожиданиям
    Если СтруктураДанных.Свойство("Products") И ТипЗнч(СтруктураДанных.Products) = Тип("Массив") Тогда
        Для Каждого ЭлементСтруктуры Из СтруктураДанных.Products Цикл
            // Создаем новую строку в таблице значений на форме
            НоваяСтрока = ЭтотОбъект.тзДанныеJSON.Добавить();    
            
            // Заполняем поля новой строки
            НоваяСтрока.id    = ЭлементСтруктуры.id;    
            НоваяСтрока.name  = ЭлементСтруктуры.name;    
            НоваяСтрока.price = ЭлементСтруктуры.price;    
            НоваяСтрока.stock = ЭлементСтруктуры.stock;    
        КонецЦикла;
    Иначе
        Сообщить("Структура JSON не содержит ожидаемого массива 'Products' или имеет неверный формат.");
        ЖурналРегистрации.Записать(
            "ОшибкаПарсингаJSON",
            УровеньЖурнала.Ошибка,
            ,
            ,
            "Неверная структура JSON: " + ДанныеJSON
        );
    КонецЕсли;

    ЧтениеJSONОбъект.Закрыть();
    Возврат Истина;
Исключение
    Сообщить("Произошла ошибка при чтении JSON: " + ОписаниеОшибки());
    ЖурналРегистрации.Записать(
        "ОшибкаПарсингаJSON",
        УровеньЖурнала.Ошибка,
        ,
        ,
        "Не удалось прочитать JSON: " + ОписаниеОшибки() + " Данные: " + ДанныеJSON
    );
    Возврат Ложь;
КонецФункции

В этой функции мы используем стандартные объекты 1С для работы с JSON:

  1. Новый ЧтениеJSON; – создает объект для чтения JSON.
  2. ЧтениеJSON.УстановитьСтроку(ДанныеJSON); – указывает, какую строку JSON следует читать.
  3. ПрочитатьJSON(ЧтениеJSON,,,,, ЭтотОбъект); – эта функция автоматически десериализует JSON в структуры и массивы 1С. Важно, чтобы JSON-строка была корректной. Второй параметр Истина при вызове ПрочитатьJSON указывает на использование совместимости с JSON RFC 4627, что полезно для более строгого соответствия стандарту.
  4. После прочтения, мы обращаемся к элементам структуры, например, Структура.Products, чтобы получить массив данных. Затем в цикле обходим этот массив и добавляем данные в строки таблицы значений формы (ЭтотОбъект.тзДанныеJSON).
  5. Также добавлен блок Попытка...Исключение для обработки возможных ошибок парсинга JSON, таких как "Непредвиденный символ при чтении JSON", если по какой-то причине полученная строка не является валидным JSON.

Для корректного вывода данных на форму, не забудьте, что таблица значений тзДанныеJSON должна быть определена как реквизит формы с соответствующими колонками (id, name, price, stock) и связана с элементом управления "Таблица" на форме.

Дополнительные рекомендации и обработка ошибок

Даже с правильной настройкой HTTPS, могут возникнуть другие проблемы. Рассмотрим, как их предотвратить и обработать:

  1. Проверка статуса ответа сервера: Как мы уже видели, критически важно проверять свойство Статус объекта HTTPОтвет.
    • 200 OK: Запрос успешно выполнен.
    • 400 Bad Request: Некорректный запрос с нашей стороны (например, неверные параметры, заголовки).
    • 401 Unauthorized: Требуется аутентификация или она не пройдена.
    • 403 Forbidden: Доступ запрещен.
    • 404 Not Found: Ресурс не найден по указанному URL.
    • 500 Internal Server Error: Ошибка на стороне сервера.
    Всегда анализируйте статус и, при неуспехе, тело ответа, чтобы понять причину.
  2. Кодировка JSON: Ошибка "Непредвиденный символ при чтении JSON" часто указывает на проблемы с кодировкой. Хотя Content-type: application/json обычно подразумевает UTF-8, сервер может вернуть данные в другой кодировке. В таких случаях можно попробовать явно указать кодировку при получении тела ответа, если это поддерживается, или выполнить перекодировку строки. Однако, в большинстве современных систем JSON передается в UTF-8.
  3. Таймаут соединения: Если сервер долго отвечает, запрос может завершиться по таймауту. В конструкторе HTTPСоединение можно явно указать таймаут в секундах, например: Новый HTTPСоединение("apps-2.v.ru", 443, "admin", "1234", 30, , Новый ЗащищенноеСоединениеOpenSSL()); (30 секунд).
  4. Использование прокси-сервера: Если доступ к внешним ресурсам осуществляется через прокси-сервер, необходимо настроить его параметры. Это можно сделать через конструктор HTTPСоединение или через глобальные настройки интернет-соединения в 1С.
  5. Оптимизация чтения JSON для больших объемов: Для большинства задач ПрочитатьJSON() является оптимальным и простым способом. Однако, для очень больших JSON-файлов, которые могут потреблять много памяти при полной десериализации, ЧтениеJSON предоставляет возможность потокового чтения. Это требует более сложной логики ручного парсинга, но может быть эффективнее для крайне больших объемов данных. В нашем случае, для получения структуры и вывода в таблицу значений, стандартный подход через ПрочитатьJSON() вполне подходит.

Заключение

Как мы видим, успешное получение JSON-данных по HTTPS-ссылке в 1С сводится к правильной настройке объекта HTTPСоединение с обязательным использованием ЗащищенноеСоединениеOpenSSL. Кроме того, критически важна надежная обработка ошибок: проверка статуса HTTP-ответа и использование блоков Попытка...Исключение. Стандартные функции ЧтениеJSON и ПрочитатьJSON значительно упрощают десериализацию данных в структуры, удобные для работы в 1С. Следуя этим рекомендациям, мы сможем эффективно интегрировать 1С с внешними системами, получая и обрабатывая необходимые данные.

← На главную