Почему HTTP-запрос в 1С возвращает HTML вместо JSON и как это исправить?

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

Разработка интеграций с внешними веб-сервисами по протоколу HTTP — одна из наиболее частых задач для современного программиста 1С. Однако на этом пути часто возникают неожиданные преграды. Типичная ситуация: один и тот же запрос в строке браузера или специализированной утилите (например, Postman) без проблем возвращает чистый JSON-пакет, но при попытке выполнить его из кода 1С платформа возвращает ответ со статусом 200 OK, тело которого представляет собой HTML-код страницы авторизации, ошибки или заглушки.

В этой статье мы подробно проанализируем причины такого поведения системы, разберем типичные ошибки при формировании запросов и научимся составлять правильный, отказоустойчивый код для взаимодействия с внешними API.

Причина 1: Путаница между Query-параметрами и HTTP-заголовками

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


Соединение = Новый HTTPСоединение("myserver.com");
Заголовки = Новый Соответствие;
Заголовки.Вставить("date_from", "01.07.2019%2000:00:00");
Заголовки.Вставить("id", "12345");
Заголовки.Вставить("format", "json");
Запрос = Новый HTTPЗапрос("api/v1/getdata", Заголовки);
Результат = Соединение.Получить(Запрос);

Давайте выясним причину, почему этот код ошибочен. В данном примере параметры фильтрации (date_from, id, format) добавляются в объект Соответствие, который передается в качестве второго параметра конструктора HTTPЗапрос. Этот параметр отвечает исключительно за HTTP-заголовки (Headers) запроса.

HTTP-заголовки передают метаданные о запросе (например, тип контента, кодировку, токены авторизации). Сами же параметры запроса (Query Parameters) должны быть частью строки адреса (URI) и следовать после знака вопроса ?. Если сервер ожидает параметры в строке запроса, но не находит их там, он либо возвращает ошибку, либо игнорирует запрос и выдает стандартную стартовую страницу (HTML).

Причина 2: Проблемы маршрутизации веб-сервера и пропущенные слэши

Предположим, мы исправили первую ошибку и перенесли параметры в строку запроса. Однако сервер все равно упорно возвращает HTML. Проанализируем типичный пример неверного конструирования пути:


// Ошибочный вариант: отсутствует слэш перед знаком вопроса
ПутьЗапроса = "api/v1/getdata?date_from=01.07.2019%2000:00:00&id=12345&format=json";
Запрос = Новый HTTPЗапрос(ПутьЗапроса);

Многие современные веб-серверы (Nginx, Apache, IIS) и бэкенд-фреймворки крайне чувствительны к наличию конечного слэша (trailing slash) перед параметрами запроса. Если ваш роутинг на сервере настроен строго на шаблон api/v1/getdata/, то запрос по пути api/v1/getdata?параметры (без слэша перед ?) может быть не распознан веб-сервером.

Что происходит в этом случае на стороне сервера? Вместо генерации ошибки 404 (Ресурс не найден), сервер может перенаправить некорректный запрос на единую точку входа (например, index.html в случае Single Page Application или CMS). В результате 1С получает код состояния 200, но в теле ответа будет лежать HTML-код главной страницы сайта.

Правильный вариант написания пути с учетом роутинга должен выглядеть так:


// Правильный вариант: слэш присутствует перед знаком вопроса
ПутьЗапроса = "api/v1/getdata/?date_from=01.07.2019%2000:00:00&id=12345&format=json";
Запрос = Новый HTTPЗапрос(ПутьЗапроса);

Причина 3: Некорректное кодирование спецсимволов (URL Encoding)

Пробелы, кириллические символы, знаки двоеточия и другие спецсимволы в строке GET-запроса должны быть обязательно закодированы в соответствии со стандартом RFC 3986. Передача «чистого» пробела или двоеточия напрямую в строке пути запроса в 1С может привести к непредсказуемому поведению сетевых библиотек операционной системы.

Для безопасного кодирования значений параметров в 1С предусмотрена встроенная функция КодироватьСтроку. Рассмотрим, как правильно формировать параметры запроса программно:


ПараметрДата = КодироватьСтроку("01.07.2019 00:00:00", СпособКодированияСтроки.КодировкаURL);
// На выходе получим безопасную строку: "01.07.2019%2000%3A00%3A00"

ПараметрИдентификатор = КодироватьСтроку("12345", СпособКодированияСтроки.КодировкаURL);
ПараметрФормат = КодироватьСтроку("json", СпособКодированияСтроки.КодировкаURL);

ПутьЗапроса = "api/v1/getdata/?" 
            + "date_from=" + ПараметрДата 
            + "&id=" + ПараметрИдентификатор 
            + "&format=" + ПараметрФормат;

Запрос = Новый HTTPЗапрос(ПутьЗапроса);

Причина 4: Игнорирование механизма согласования содержимого (Accept)

Иногда веб-сервер умеет отдавать данные в разных форматах: HTML (для браузеров), XML или JSON (для интеграций). По умолчанию сервер пытается определить тип клиента по заголовку User-Agent. Так как 1С отправляет специфичный заголовок, сервер может посчитать её обычным браузером и вернуть красивую HTML-страничку вместо сырых данных.

Чтобы явно указать серверу, какой тип контента мы ожидаем получить в ответ, необходимо использовать заголовок согласования содержимого Accept. Обратите внимание, что заголовок Content-Type указывает серверу тип отправляемых нами данных, в то время как Accept — тип ожидаемых данных.

Добавим этот важный заголовок в наш запрос:


Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept", "application/json");

Запрос = Новый HTTPЗапрос(ПутьЗапроса, Заголовки);

Причина 5: Автоматический редирект с HTTP на HTTPS

Если вы отправляете запрос на незащищенный адрес http://myserver.com, а сервер настроен на обязательное шифрование трафика, он автоматически перенаправит ваш запрос на https://myserver.com.

Современные браузеры делают этот переход (редирект со статусом 301 или 302) незаметно для пользователя. Однако объект HTTPСоединение в платформе 1С автоматически переходы не выполняет. Он честно вернет вам ответ сервера с кодом перенаправления и HTML-страницей, на которой будет написано что-то вроде "Document has moved".

Чтобы избежать этой проблемы, всегда используйте защищенное соединение https с инициализацией SSL-сертификатов:


SSLСоединение = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("myserver.com", 443, , , , , SSLСоединение);

Собираем все вместе: идеальный шаблон для выполнения HTTP GET-запроса

Давайте объединим все полученные знания в единую, готовую к использованию функцию. Мы автоматизируем сборку параметров, их кодирование, установку заголовков и обработку результата.


Функция ВыполнитьЗапросПолученияДанных() Экспорт

    Сервер = "myserver.com";
    Ресурс = "api/v1/getdata/"; // Обязательно закрываем слэшем перед параметрами
    
    // Подготавливаем структуру параметров запроса
    Параметры = Новый Структура;
    Параметры.Вставить("date_from", "01.07.2019 00:00:00");
    Параметры.Вставить("id", "12345");
    Параметры.Вставить("format", "json");
    
    // Собираем строку параметров с URL-кодированием
    СтрокаПараметров = "";
    Для Каждого ТекПараметр Из Параметры Цикл
        ИмяБезПробелов = СокрЛП(ТекПараметр.Ключ);
        ЗначениеКодированное = КодироватьСтроку(Строка(ТекПараметр.Значение), СпособКодированияСтроки.КодировкаURL);
        
        Разделитель = ?(ЗначениеЗаполнено(СтрокаПараметров), "&", "");
        СтрокаПараметров = СтрокаПараметров + Разделитель + ИмяБезПробелов + "=" + ЗначениеКодированное;
    КонецЦикла;
    
    ПолныйПутьРесурса = Ресурс + "?" + СтрокаПараметров;
    
    // Задаем необходимые заголовки для получения JSON
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Accept", "application/json");
    
    // Инициализируем защищенное HTTPS соединение
    SSL = Новый ЗащищенноеСоединениеOpenSSL();
    Соединение = Новый HTTPСоединение(Сервер, 443, , , , 15, SSL);
    
    Запрос = Новый HTTPЗапрос(ПолныйПутьРесурса, Заголовки);
    
    Попытка
        Ответ = Соединение.Получить(Запрос);
        КодСостояния = Ответ.КодСостояния;
        
        Если КодСостояния = 200 Тогда
            ДанныеJSON = Ответ.ПолучитьТелоКакСтроку("UTF-8");
            Возврат ДанныеJSON;
        Иначе
            ВызватьИсключение "Сервер вернул код ошибки: " + КодСостояния;
        КонецЕсли;
    Исключение
        ЗаписьЖурналаРегистрации("ИнтеграцияHTTP", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
        Возврат Неопределено;
    КонецПопытки;

КонецФункции

Как отлаживать HTTP-запросы в 1С "для чайников"?

Если код написан правильно, но сервер всё равно возвращает непредвиденный результат, необходимо посмотреть на отправляемый запрос «глазами сервера». Для этого используются специализированные локальные прокси-серверы (снифферы трафика). Самым простым и мощным инструментом является программа Fiddler Classic.

Рассмотрим пошагово, как перехватить запрос из 1С с помощью Fiddler:

  1. Скачайте и установите программу Fiddler Classic на ваш рабочий компьютер.
  2. Запустите Fiddler. По умолчанию он начинает прослушивать локальный порт 8888.
  3. Платформа 1С отправляет запросы в обход системного прокси-сервера. Чтобы направить трафик из 1С в Fiddler, нам нужно явно указать прокси-сервер в коде инициализации соединения:

// Указываем локальный прокси-сервер запущенного Fiddler
ПроксиСервер = Новый HTTPПрокси("127.0.0.1", 8888);

// Передаем прокси в конструктор HTTPСоединения
Соединение = Новый HTTPСоединение("myserver.com", , , , ПроксиСервер);

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

← На главную