Как получить данные из HTTP-сервиса 1С в формате JSON и исправить ошибку 401?

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

Разработка двустороннего обмена данными между базами 1С или между 1С и сторонним сайтом — одна из самых частых задач современного программиста. Использование технологии HTTP-сервисов и формата передачи данных JSON является промышленным стандартом. Однако на начальном этапе разработчики часто сталкиваются с классическими архитектурными ошибками, путаницей в HTTP-методах (GET/POST) и проблемами с авторизацией (ошибка 401 Unauthorized).

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

Анализируем проблему: почему возникает ошибка 401 и путаница с GET/POST

Рассмотрим ситуацию, с которой столкнулся автор темы. На стороне базы-источника опубликован HTTP-сервис с методом GET. При обращении через обычный браузер по адресу http://localhost/Test_HTTP_1/hs/info?action=getrooms он успешно получает данные в формате JSON. Но при попытке прочитать эти же данные из другой базы 1С с помощью программного кода возникает ошибка 401 Unauthorized.

Проанализируем исходный код автора, содержащий критические ошибки:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    Адрес = "http://localhost/Test_HTTP_1/hs/info?action=getrooms";
    ПарамОтвет = Новый Структура;
    ВыполнитьHTTPЗапрос(Адрес, "", "POST", ПарамОтвет);
    
    Если Сред(ПарамОтвет.Ошибка, 1, 28) = "КодСостояния HTTP-запроса: 2" Тогда
        Чтение = Новый ЧтениеJSON;
        Чтение.УстановитьСтроку(ПарамОтвет.Ответ);
        Структ = ПрочитатьJSON(Чтение, Истина);
        
    Иначе
        Сообщить(ПарамОтвет.Ошибка)
    КонецЕсли;    
КонецПроцедуры

В этом примере кода отчетливо видны три проблемы:

  1. Несоответствие HTTP-методов: Сервис опубликован и ожидает метод GET (что подтверждается успешным открытием в браузере), а программный запрос отправляется методом POST. В концепции REST API метод GET используется исключительно для безопасного и неизменяемого чтения данных, тогда как POST служит для отправки новой информации на сервер. Пытаться прочитать данные методом POST с ресурса, настроенного только на GET, — архитектурная ошибка.
  2. Проблема с авторизацией (Код 401): Ошибка 401 означает, что веб-сервер (IIS или Apache) отклонил запрос из-за отсутствия или некорректности учетных данных. При работе через браузер у пользователя могла сработать кэшированная авторизация или доменная Windows-авторизация, в то время как программный запрос из 1С отправляется абсолютно "анонимным". Для исправления этой ошибки в коде необходимо явно передавать имя пользователя и пароль.
  3. Использование устаревших "оберток": Функция ВыполнитьHTTPЗапрос является устаревшей самописной процедурой. Современная платформа 1С v8.3 предоставляет мощные и удобные объектные механизмы: HTTPСоединение, HTTPЗапрос и HTTPОтвет, которые делают код прозрачным и легким для отладки.

Шаг 1. Настраиваем авторизацию и исправляем ошибку 401

Для того чтобы принимающая база 1С могла успешно авторизоваться на веб-сервере, нам нужно передать учетные данные. Существует два основных способа решения этой проблемы.

Способ А. Передача учетных данных через HTTPСоединение (рекомендуется)

Самый надежный и безопасный вариант — использовать Basic-авторизацию, передавая имя пользователя и пароль непосредственно при инициализации соединения. Обратите внимание на важный нюанс: имя пользователя в 1С для веб-обменов настоятельно рекомендуется писать латиницей. Использование кириллических логинов часто приводит к искажению кодировки при конвертации заголовков на стороне веб-сервера.

Способ Б. Настройка файла публикации default.vrd

Если веб-сервис должен отдавать данные без требования ввода логина и пароля со стороны клиента (например, при интеграции с внешним сайтом, который не умеет хранить сложные реквизиты авторизации), можно прописать системного пользователя в файле публикации default.vrd. Для этого в строке подключения информационной базы укажите параметры usr и pwd:


<ib connection="Srvr=&quot;server1c&quot;;Ref=&quot;test_db&quot;;usr=&quot;WebUser&quot;;pwd=&quot;StrongPassword123&quot;;"/>

В этом случае любые внешние запросы к публикации будут автоматически выполняться в контексте прав пользователя WebUser. Тем не менее, для обмена "1С-to-1С" первый способ с явным указанием учетных данных в коде является более предпочтительным и безопасным.

Шаг 2. Пишем правильный код получения данных из HTTP-сервиса

Давайте откажемся от использования устаревших функций-оберток и напишем современный, чистый код на платформе 1С v8.3. Мы разберем процесс по шагам: создание соединения, отправка GET-запроса, разбор полученного JSON-ответа.


&НаКлиенте
Процедура ПолучитьДанныеОНомерах(Команда)
    
    // Выносим тяжелые серверные вызовы на сервер
    ПолучитьДанныеОНомерахНаСервере();
    
КонецПроцедуры

&НаСервере
Процедура ПолучитьДанныеОНомерахНаСервере()
    
    // Шаг 1. Определяем параметры подключения к веб-серверу
    Сервер = "localhost";
    Порт = 80; // Для HTTPS обычно используется 443
    Пользователь = "WebExchangeUser";
    Пароль = "MySecurePassword125";
    
    // Шаг 2. Создаем HTTP-соединение с авторизацией
    // За счет передачи логина и пароля мы полностью избегаем ошибки 401
    Соединение = Новый HTTPСоединение(Сервер, Порт, Пользователь, Пароль);
    
    // Шаг 3. Формируем относительный адрес ресурса (URI)
    // Метод GET позволяет передавать параметры прямо в строке запроса после знака "?"
    АдресРесурса = "/Test_HTTP_1/hs/info?action=getrooms";
    
    Запрос = Новый HTTPЗапрос(АдресРесурса);
    
    // При необходимости можно явно задать заголовки, сообщающие серверу, какой тип контента мы ожидаем
    Запрос.Заголовки.Вставить("Accept", "application/json");
    
    Попытка
        // Шаг 4. Выполняем GET-запрос
        Ответ = Соединение.Получить(Запрос);
        
        // Шаг 5. Анализируем код состояния ответа сервера
        Если Ответ.КодСостояния = 200 Тогда // 200 OK — запрос выполнен успешно
            
            // Получаем тело ответа в виде строки в кодировке UTF-8
            СтрокаJSON = Ответ.ПолучитьТелоКакСтроку("UTF-8");
            
            // Переходим к разбору JSON-структуры
            ОбработатьПолученныйJSON(СтрокаJSON);
            
        Иначе
            // Обрабатываем другие коды состояния (например, 401, 404, 500)
            ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Ошибка, , , 
                "Не удалось получить данные. Код состояния сервера: " + Ответ.КодСостояния);
            ВызватьИсключение "Ошибка обмена! Сервер вернул код: " + Ответ.КодСостояния;
        КонецЕсли;
        
    Исключение
        // Перехватываем сетевые ошибки (недоступность сервера, таймаут и т.д.)
        ЗаписьЖурналаРегистрации("HTTP-Обмен", УровеньЖурналаРегистрации.Ошибка, , , 
            "Сетевая ошибка при выполнении запроса: " + ОписаниеОшибки());
        ВызватьИсключение "Ошибка сетевого соединения с сервером!";
    КонецПопытки;
    
КонецПроцедуры

Шаг 3. Чтение и десериализация JSON в объекты 1С

После того как мы успешно получили строку JSON, её необходимо преобразовать в понятные для 1С структуры данных (Массивы, Соответствия или Структуры). Разберем, как правильно использовать встроенный объект ЧтениеJSON.

Посмотрим на структуру JSON, которую прислал сервер в примере автора:


[
  {
    "date_begin": "2019.10.10",
    "date_end": "2019.10.16",
    "seats": 2,
    "seats_child": 0,
    "check_in": 1,
    "check_out": 1,
    "nutrition": "hb"
  }
]

Данный JSON представляет собой массив объектов. Напишем процедуру для разбора этой структуры:


&НаСервере
Процедура ОбработатьПолученныйJSON(Знач СтрокаJSON)
    
    // Инициализируем объект чтения JSON
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаJSON);
    
    // Читаем JSON в переменные 1С. 
    // Второй параметр "Ложь" указывает, что объекты JSON преобразуются в Структуры 1С.
    // Если ключи в JSON содержат недопустимые для свойств Структуры символы (например, дефисы),
    // следует передать "Истина", тогда объекты преобразуются в Соответствия.
    ДанныеОбмена = ПрочитатьJSON(Чтение, Ложь);
    Чтение.Закрыть();
    
    // Поскольку корень нашего JSON — это массив (обозначен квадратными скобками []), 
    // в 1С мы получили переменную с типом "Массив", элементами которого являются "Структуры".
    Если ТипЗнч(ДанныеОбмена) = Тип("Массив") Тогда
        
        Для Каждого ДанныеНомера Из ДанныеОбмена Цикл
            
            // Извлекаем свойства из структуры
            ДатаНачалаСтрока  = ДанныеНомера.date_begin; // Получаем строку "2019.10.10"
            ДатаОкончанияСтрока = ДанныеНомера.date_end;   // Получаем строку "2019.10.16"
            КоличествоМест    = ДанныеНомера.seats;       // Получаем Число 2
            Питание           = ДанныеНомера.nutrition;   // Получаем Строку "hb"
            
            // В JSON даты передаются как строки. Преобразуем их в тип Дата 1С вручную
            ДатаНачала = ПреобразоватьСтрокуВДату(ДатаНачалаСтрока);
            ДатаОкончания = ПреобразоватьСтрокуВДату(ДатаОкончанияСтрока);
            
            // Здесь пишем бизнес-логику: запись в регистр сведений, создание документов "Бронирование" и т.д.
            Сообщить(СтрШаблон("Успешно обработан номер. Период: %1 - %2. Мест: %3", 
                Формат(ДатаНачала, "ДФ=dd.MM.yyyy"), 
                Формат(ДатаОкончания, "ДФ=dd.MM.yyyy"), 
                КоличествоМест));
                
        КонецЦикла;
        
    Иначе
        ВызватьИсключение "Неверный формат данных: ожидался массив объектов.";
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Функция ПреобразоватьСтрокуВДату(Знач СтрокаДаты)
    
    // Преобразует формат "ГГГГ.ММ.ДД" в стандартную дату 1С.
    // Очищаем строку от возможных пробелов
    СтрокаДаты = СокрЛП(СтрокаДаты); 
    Если СтрДлина(СтрокаДаты) = 10 Тогда
        ЧастиДаты = СтрРазделить(СтрокаДаты, ".");
        Если ЧастиДаты.Количество() = 3 Тогда
            Возврат Дата(ЧастиДаты[0], ЧастиДаты[1], ЧастиДаты[2]);
        КонецЕсли;
    КонецЕсли;
    
    Возврат '00010101'; // Если дата не распознана, возвращаем пустую дату
КонецФункции

Рекомендации по безопасности и стабильности интеграции

Для создания надежного и отказоустойчивого двустороннего обмена рекомендуем придерживаться следующих правил:

Используя предложенные методики и современные объекты платформы 1С, вы сможете быстро и элегантно развернуть стабильный обмен данными, не прибегая к использованию непрозрачных сторонних библиотек и устаревших функций.

← На главную