Почему 1С не передает пользовательские HTTP-заголовки с пустыми значениями при использовании метода HTTPСоединение.Получить()?

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

При работе с внешними сервисами и интеграциями в 1С мы часто сталкиваемся с необходимостью отправлять HTTP-запросы, содержащие не только тело запроса, но и специфические заголовки. Метод HTTPСоединение.Получить() предназначен для выполнения GET-запросов и позволяет передавать в них пользовательские заголовки. Однако, как показал опыт наших коллег, в определенных ситуациях 1С может игнорировать некоторые из этих заголовков, что приводит к некорректной работе интеграции. Давайте разберем эту проблему подробнее и выясним, почему такое происходит и как это исправить.

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

Один из наших коллег столкнулся с тем, что при отправке HTTP-запроса из 1С с помощью HTTPСоединение.Получить() некоторые пользовательские заголовки, такие как "DeviceID" и "UserID", не достигали целевого сервера. При этом стандартный заголовок "Content-Type", хоть и с измененным значением, передавался успешно. Это вызвало недоумение, поскольку код, казалось бы, был написан корректно.

Рассмотрим пример кода, который использовался изначально:


HTTPСоединение = Новый HTTPСоединение(Константы.АдресСервера.Получить(), 80,,,,ТаймАутСоединения); 
   
Заголовок = Новый Соответствие; 
Заголовок.Вставить("Content-Type", "application/json/test");
Заголовок.Вставить("DeviceID", СокрЛП(Константы.ИдентификаторУстройства.Получить()));
Заголовок.Вставить("UserID", СокрЛП(Константы.ИдентификаторПользователя.Получить()));
HTTPЗапрос    = Новый HTTPЗапрос(ХттпЗапрос, Заголовок); 
Результат     = HTTPСоединение.Получить(HTTPЗапрос); //GET
ОтветОтСервера    = Результат.ПолучитьТелоКакСтроку();

В этом коде мы создаем объект HTTPСоединение, затем формируем коллекцию заголовков с помощью объекта Соответствие и передаем её в конструктор HTTPЗапрос. После этого выполняем запрос методом Получить(). Проверка на стороне сервера показала, что "Content-Type" передается, а "DeviceID" и "UserID" – нет.

Выясняем причину: обработка пустых значений заголовков

Первоначальные предположения касались наличия прокси-серверов, которые могли бы отфильтровывать нестандартные заголовки, или необходимости использования префикса "X-" для пользовательских заголовков, но эти версии не подтвердились. Прокси отсутствовал, а использование метода ВызватьМетод() вместо Получить() давало тот же результат.

Ключевой момент выяснился в ходе дальнейшего анализа. Было высказано предположение, что платформа 1С может отрезать заголовки, если их значения являются пустыми строками. Автор подтвердил, что значения констант Константы.ИдентификаторУстройства.Получить() и Константы.ИдентификаторПользователя.Получить() действительно могли быть пустыми, а функция СокрЛП() в этом случае также возвращает пустую строку.

Мы должны понимать, что хотя стандарты HTTP напрямую не запрещают отправку заголовков с пустым значением, на практике многие HTTP-клиенты, включая реализацию в 1С, могут игнорировать или отбрасывать такие заголовки. Это может быть связано с оптимизацией, чтобы не передавать "бессмысленные" данные, или с особенностями внутренней реализации. Пустое строковое значение может быть интерпретировано как отсутствие заголовка или как указание на его отключение.

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

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

Мы можем проверить это, подставив заведомо непустые значения, например, тестовые строки. После такой проверки автор подтвердил, что с заполненными значениями заголовки начали передаваться корректно.

Давайте рассмотрим, как можно модифицировать код, чтобы избежать этой проблемы:

  1. Проверка на пустое значение перед вставкой: Самый надежный способ — это проверять значение переменной или константы перед тем, как добавлять заголовок в коллекцию Соответствие.
  2. Заполнение констант/переменных: Убедитесь, что константы или переменные, из которых берутся значения для заголовков, всегда содержат актуальные и непустые данные.

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


HTTPСоединение = Новый HTTPСоединение(Константы.АдресСервера.Получить(), 80,,,,ТаймАутСоединения); 
   
Заголовок = Новый Соответствие; 
Заголовок.Вставить("Content-Type", "application/json/test"); // Этот заголовок обычно всегда имеет значение

ИдентификаторУстройства = СокрЛП(Константы.ИдентификаторУстройства.Получить());
Если Не ПустаяСтрока(ИдентификаторУстройства) Тогда
    Заголовок.Вставить("DeviceID", ИдентификаторУстройства);
КонецЕсли;

ИдентификаторПользователя = СокрЛП(Константы.ИдентификаторПользователя.Получить());
Если Не ПустаяСтрока(ИдентификаторПользователя) Тогда
    Заголовок.Вставить("UserID", ИдентификаторПользователя);
КонецЕсли;

HTTPЗапрос    = Новый HTTPЗапрос(ХттпЗапрос, Заголовок); 
Результат     = HTTPСоединение.Получить(HTTPЗапрос); //GET
ОтветОтСервера    = Результат.ПолучитьТелоКакСтроку();

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

Альтернативные подходы к передаче данных

Хотя проблема с пустыми заголовками решена, мы также можем рассмотреть альтернативные способы передачи данных, особенно если эти данные не критичны для HTTP-протокола и могут быть частью URL-адреса запроса. Например, параметры "DeviceID" и "UserID" можно передавать как параметры GET-запроса в строке URL:


// Предположим, что ХттпЗапрос = "/api/data"
ИдентификаторУстройства = СокрЛП(Константы.ИдентификаторУстройства.Получить());
ИдентификаторПользователя = СокрЛП(Константы.ИдентификаторПользователя.Получить());

ПараметрыURL = Новый Соответствие;
Если Не ПустаяСтрока(ИдентификаторУстройства) Тогда
    ПараметрыURL.Вставить("deviceID", ИдентификаторУстройства);
КонецЕсли;
Если Не ПустаяСтрока(ИдентификаторПользователя) Тогда
    ПараметрыURL.Вставить("userID", ИдентификаторПользователя);
КонецЕсли;

СтрокаПараметров = "";
Для Каждого Параметр Из ПараметрыURL Цикл
    Если СтрокаПараметров <> "" Тогда
        СтрокаПараметров = СтрокаПараметров + "&";
    Иначе
        СтрокаПараметров = "?";
    КонецЕсли;
    СтрокаПараметров = СтрокаПараметров + Параметр.Ключ + "=" + Параметр.Значение;
КонецЦикла;

ПолныйРесурс = ХттпЗапрос + СтрокаПараметров;
   
HTTPСоединение = Новый HTTPСоединение(Константы.АдресСервера.Получить(), 80,,,,ТаймАутСоединения); 
   
Заголовок = Новый Соответствие; 
Заголовок.Вставить("Content-Type", "application/json/test");
   
HTTPЗапрос    = Новый HTTPЗапрос(ПолныйРесурс, Заголовок); 
Результат     = HTTPСоединение.Получить(HTTPЗапрос); 
ОтветОтСервера    = Результат.ПолучитьТелоКакСтроку();

Этот подход может быть более надежным для передачи необязательных параметров, которые не являются частью стандартных HTTP-заголовков, особенно если принимающий сервер специально ожидает их в URL. Однако выбор между заголовками и параметрами URL всегда зависит от требований API целевого сервера.

Важные выводы и рекомендации

Из этой ситуации мы можем сделать несколько важных выводов и дать рекомендации по работе с HTTP-запросами в 1С:

  1. Всегда проверяйте значения заголовков: Перед отправкой убедитесь, что все пользовательские HTTP-заголовки имеют непустые значения. Платформа 1С может отбрасывать заголовки с пустыми строковыми значениями при формировании запроса.
  2. Проверяйте логи на стороне сервера: Если у вас есть доступ к серверной части (как в данном случае, когда сервер тоже на 1С), всегда проверяйте входящие заголовки и параметры запроса. Это поможет быстро локализовать проблему.
  3. Используйте функции для обработки строк: Функции типа СокрЛП() полезны, но помните, что они могут вернуть пустую строку, если исходное значение пусто или состоит только из пробелов.
  4. Помните о контексте: Выбор между передачей данных в заголовках, теле запроса или параметрах URL зависит от требований API, с которым вы взаимодействуете. Всегда обращайтесь к документации внешнего сервиса.

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

← На главную