Как отправить массив значений и вложенные структуры в POST запросе типа `application/x-www-form-urlencoded` из 1С?

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

При интеграции 1С с внешними веб-сервисами, часто возникает необходимость отправлять данные в формате POST-запроса. Если сервис ожидает данные не в привычном для 1С JSON-формате, а в виде URL-кодированной строки (application/x-www-form-urlencoded), да еще и с вложенными массивами или структурами, задача усложняется. В этом руководстве мы подробно разберем, как сформировать такой запрос, используя встроенные средства 1С.

Суть проблемы: Отличие JSON от URL-кодированной строки с вложенными структурами

Начнем с анализа того, почему стандартные подходы 1С к формированию JSON-строк не подходят для данного случая. Представим, что внешний сервис ожидает данные, которые в curl запросе выглядят так:


'name' => 'имя', 
'type_id' => '1', 
'massive1' => [ 
    'color' => [ 
        2 => 'желтый', 
        3 => 'зеленый', 
    ] 
]

Если мы попытаемся отправить это как JSON, мы получим структуру вида:


{
    "name": "имя",
    "type_id": "1",
    "massive1": {
        "color": {
            "2": "желтый",
            "3": "зеленый"
        }
    }
}

Однако, как показывает опыт многих разработчиков, а также сообщения в обсуждаемой теме, зачастую сервис ожидает совершенно другой формат, а именно URL-кодированную строку, которая представляет вложенные массивы и объекты с использованием квадратных скобок []. Корректный формат для тела POST-запроса, который успешно парсится такими серверами (например, на PHP), будет выглядеть так:

name=имя&type_id=1&massive1[color][2]=желтый&massive1[color][3]=зеленый

Здесь massive1 воспринимается как ассоциативный массив или объект, содержащий поле color, которое, в свою очередь, является еще одним ассоциативным массивом, где 2 и 3 — это ключи (а не индексы обычного массива), а "желтый" и "зеленый" — их значения. Ключевое отличие заключается в использовании синтаксиса [ключ] вместо простого перечисления полей или использования JSON-объектов.

Встроенные средства 1С, такие как объекты ЗаписьJSON или функции для работы с XML, не предоставляют готовых инструментов для автоматической сериализации сложных структур данных в этот специфический формат application/x-www-form-urlencoded с квадратными скобками. Следовательно, нам придется формировать эту строку вручную.

Пошаговое формирование URL-кодированной строки в 1С

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

  1. Представление исходных данных: В 1С мы можем представить наши данные в виде вложенных Соответствий и Массивов, максимально приближенных к структуре, которую хотим получить в URL-кодированном виде.
  2. 
    // Шаг 1: Подготовка исходных данных в 1С
    ДанныеЗапроса = Новый Соответствие;
    ДанныеЗапроса.Вставить("name", "имя");
    ДанныеЗапроса.Вставить("type_id", "1");
    
    Массив1Цвета = Новый Соответствие;
    Массив1Цвета.Вставить("2", "желтый"); // Ключи 2 и 3 явно указываются
    Массив1Цвета.Вставить("3", "зеленый");
    
    Массив1 = Новый Соответствие;
    Массив1.Вставить("color", Массив1Цвета);
    
    ДанныеЗапроса.Вставить("massive1", Массив1);
    

Мы видим, что ДанныеЗапроса содержит простые пары ключ-значение и вложенные Соответствия для massive1 и color.

Создание рекурсивной функции для формирования строки

Мы предлагаем создать универсальную функцию, которая сможет рекурсивно обходить вашу структуру данных (Соответствия и Массивы) и формировать необходимую URL-кодированную строку. Рассмотрим ее подробнее.


&НаКлиенте
Функция СформироватьURLКодированнуюСтроку(Данные, ПрефиксКлюча = "")
    СтрокаПараметров = Новый Массив;

    Если ТипЗнч(Данные) = Тип("Соответствие") Тогда
        Для Каждого Элемент Из Данные Цикл
            Ключ = Элемент.Ключ;
            Значение = Элемент.Значение;

            // Формируем новый префикс ключа для вложенных структур
            Перем НовыйПрефикс;
            Если ПустаяСтрока(ПрефиксКлюча) Тогда
                // Для первого уровня не добавляем скобки, просто используем ключ
                НовыйПрефикс = Ключ;
            Иначе
                // Для вложенных уровней добавляем ключ в квадратных скобках
                НовыйПрефикс = ПрефиксКлюча + "[" + Ключ + "]";
            КонецЕсли;

            // Рекурсивно обрабатываем вложенные Соответствия или Массивы
            Если ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
                СтрокаПараметров.Добавить(СформироватьURLКодированнуюСтроку(Значение, НовыйПрефикс));
            Иначе
                // Кодируем значение и добавляем пару ключ=значение
                СтрокаПараметров.Добавить(НовыйПрефикс + "=" + КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL));
            КонецЕсли;
        КонецЦикла;
    ИначеЕсли ТипЗнч(Данные) = Тип("Массив") Тогда
        // Обработка обычных массивов (элементы по индексу)
        Для Индекс = 0 По Данные.ВВерхняяГраница() Цикл
            Значение = Данные[Индекс];
            // Для элементов массива используем индекс в квадратных скобках
            НовыйПрефикс = ПрефиксКлюча + "[" + Индекс + "]";

            // Рекурсивно обрабатываем вложенные Соответствия или Массивы
            Если ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
                СтрокаПараметров.Добавить(СформироватьURLКодированнуюСтроку(Значение, НовыйПрефикс));
            Иначе
                // Кодируем значение и добавляем пару ключ=значение
                СтрокаПараметров.Добавить(НовыйПрефикс + "=" + КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL));
            КонецЕсли;
        КонецЦикла;
    Иначе
        // Обработка простых значений, если функция вызывается для них напрямую
        // (хотя обычно вызывается для Соответствия или Массива)
        Если Не ПустаяСтрока(ПрефиксКлюча) Тогда
            СтрокаПараметров.Добавить(ПрефиксКлюча + "=" + КодироватьСтроку(Данные, СпособКодированияСтроки.КодировкаURL));
        КонецЕсли;
    КонецЕсли;

    // Объединяем все полученные фрагменты строки с помощью амперсанда
    Возврат СтроковыеФункции.Объединить(СтрокаПараметров, "&");
КонецФункции

Как работает функция:

Настройка и отправка HTTP-запроса в 1С

После того как мы сформировали нужную строку тела запроса, нам необходимо правильно настроить и отправить HTTP-запрос в 1С.

  1. Формирование тела запроса: Вызовем нашу функцию СформироватьURLКодированнуюСтроку с подготовленными данными.
  2. 
    СтрокаТелаЗапроса = СформироватьURLКодированнуюСтроку(ДанныеЗапроса);
    // СтрокаТелаЗапроса будет иметь вид: "name=имя&type_id=1&massive1[color][2]=желтый&massive1[color][3]=зеленый" (после кодирования значений)
    
  3. Настройка заголовков HTTP-запроса: Обязательно установим заголовок Content-Type в значение application/x-www-form-urlencoded. Это сообщает серверу, какой тип данных он должен ожидать в теле запроса.
  4. 
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
    
  5. Создание и отправка HTTP-запроса: Используем объекты HTTPЗапрос и HTTPСоединение для отправки запроса.
  6. 
    // Шаг 3: Создание и отправка HTTP-запроса
    ЗапросВ = Новый HTTPЗапрос;
    ЗапросВ.Заголовки = Заголовки; // Присваиваем сформированные заголовки
    
    // Устанавливаем тело запроса из строки, указывая кодировку
    // Важно: для латиницы и цифр можно использовать КодировкаТекста.ANSI,
    // но для кириллицы лучше КодировкаТекста.UTF8
    ЗапросВ.УстановитьТелоИзСтроки(СтрокаТелаЗапроса, КодировкаТекста.UTF8);
    
    // Пример URL-адреса и порта для соединения (замените на свои)
    ИмяСервера = "example.com"; 
    ПортСервера = 443; // Для HTTPS
        
    // Создаем защищенное соединение для HTTPS
    Соединение = Новый HTTPСоединение(ИмяСервера, ПортСервера, , , , , Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено));
    
    Попытка
        Ответ = Соединение.Отправить(ЗапросВ);
    
        Если Ответ.КодСостояния = 200 Тогда
            Сообщить("Запрос успешно отправлен. Ответ: " + Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
        Иначе
            Сообщить("Ошибка при отправке запроса. Код состояния: " + Ответ.КодСостояния);
            Сообщить("Текст ошибки: " + Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
        КонецЕсли;
    Исключение
        Сообщить("Произошла ошибка при выполнении HTTP-запроса: " + ОписаниеОшибки());
    КонецПопытки;
    

Обратите внимание, что для HTTPS-соединений необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Если ваш сервис работает по HTTP, то достаточно Новый HTTPСоединение(...) без последнего параметра.

Важные моменты и возможные доработки

Таким образом, хотя 1С не предоставляет готовой "коробки" для сериализации сложных структур в application/x-www-form-urlencoded, мы можем эффективно решить эту задачу, написав собственную рекурсивную функцию. Этот подход является гибким и позволяет адаптироваться к специфическим требованиям различных веб-сервисов.

← На главную