При интеграции 1С с внешними веб-сервисами, часто возникает необходимость отправлять данные в формате POST-запроса. Если сервис ожидает данные не в привычном для 1С JSON-формате, а в виде URL-кодированной строки (application/x-www-form-urlencoded), да еще и с вложенными массивами или структурами, задача усложняется. В этом руководстве мы подробно разберем, как сформировать такой запрос, используя встроенные средства 1С.
Начнем с анализа того, почему стандартные подходы 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 с квадратными скобками. Следовательно, нам придется формировать эту строку вручную.
Для создания требуемой строки запроса в 1С мы будем использовать итерацию по нашим данным (представленным, например, в виде Соответствия или Массива) и рекурсивное формирование строковых фрагментов. Разберем этот процесс по шагам.
Соответствий и Массивов, максимально приближенных к структуре, которую хотим получить в URL-кодированном виде.
// Шаг 1: Подготовка исходных данных в 1С
ДанныеЗапроса = Новый Соответствие;
ДанныеЗапроса.Вставить("name", "имя");
ДанныеЗапроса.Вставить("type_id", "1");
Массив1Цвета = Новый Соответствие;
Массив1Цвета.Вставить("2", "желтый"); // Ключи 2 и 3 явно указываются
Массив1Цвета.Вставить("3", "зеленый");
Массив1 = Новый Соответствие;
Массив1.Вставить("color", Массив1Цвета);
ДанныеЗапроса.Вставить("massive1", Массив1);
Мы видим, что ДанныеЗапроса содержит простые пары ключ-значение и вложенные Соответствия для massive1 и color.
ключ=значение. Для вложенных структур ключи должны быть составными, например, massive1[color][2]. Это требует рекурсивного подхода.КодироватьСтроку с параметром СпособКодированияСтроки.КодировкаURL для каждого значения. Это обеспечит правильную передачу данных, особенно если они содержат пробелы, кириллицу или специальные символы. Например, строка "желтый" после кодирования станет %D0%B6%D0%B5%D0%BB%D1%82%D1%8B%D0%B9. При необходимости, сложные части ключей также могут быть закодированы, но обычно этого не требуется для стандартных имен полей.ключ=значение (уже URL-кодированные) следует объединить символом &.Мы предлагаем создать универсальную функцию, которая сможет рекурсивно обходить вашу структуру данных (Соответствия и Массивы) и формировать необходимую URL-кодированную строку. Рассмотрим ее подробнее.
&НаКлиенте
Функция СформироватьURLКодированнуюСтроку(Данные, ПрефиксКлюча = "")
СтрокаПараметров = Новый Массив;
Если ТипЗнч(Данные) = Тип("Соответствие") Тогда
Для Каждого Элемент Из Данные Цикл
Ключ = Элемент.Ключ;
Значение = Элемент.Значение;
// Формируем новый префикс ключа для вложенных структур
Перем НовыйПрефикс;
Если ПустаяСтрока(ПрефиксКлюча) Тогда
// Для первого уровня не добавляем скобки, просто используем ключ
НовыйПрефикс = Ключ;
Иначе
// Для вложенных уровней добавляем ключ в квадратных скобках
НовыйПрефикс = ПрефиксКлюча + "[" + Ключ + "]";
КонецЕсли;
// Рекурсивно обрабатываем вложенные Соответствия или Массивы
Если ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
СтрокаПараметров.Добавить(СформироватьURLКодированнуюСтроку(Значение, НовыйПрефикс));
Иначе
// Кодируем значение и добавляем пару ключ=значение
СтрокаПараметров.Добавить(НовыйПрефикс + "=" + КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL));
КонецЕсли;
КонецЦикла;
ИначеЕсли ТипЗнч(Данные) = Тип("Массив") Тогда
// Обработка обычных массивов (элементы по индексу)
Для Индекс = 0 По Данные.ВВерхняяГраница() Цикл
Значение = Данные[Индекс];
// Для элементов массива используем индекс в квадратных скобках
НовыйПрефикс = ПрефиксКлюча + "[" + Индекс + "]";
// Рекурсивно обрабатываем вложенные Соответствия или Массивы
Если ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
СтрокаПараметров.Добавить(СформироватьURLКодированнуюСтроку(Значение, НовыйПрефикс));
Иначе
// Кодируем значение и добавляем пару ключ=значение
СтрокаПараметров.Добавить(НовыйПрефикс + "=" + КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL));
КонецЕсли;
КонецЦикла;
Иначе
// Обработка простых значений, если функция вызывается для них напрямую
// (хотя обычно вызывается для Соответствия или Массива)
Если Не ПустаяСтрока(ПрефиксКлюча) Тогда
СтрокаПараметров.Добавить(ПрефиксКлюча + "=" + КодироватьСтроку(Данные, СпособКодированияСтроки.КодировкаURL));
КонецЕсли;
КонецЕсли;
// Объединяем все полученные фрагменты строки с помощью амперсанда
Возврат СтроковыеФункции.Объединить(СтрокаПараметров, "&");
КонецФункции
Данные (Соответствие или Массив, который нужно сериализовать) и ПрефиксКлюча, который используется для построения полного имени параметра для вложенных структур.Соответствие, она итерирует по его ключам и значениям. Если это Массив, она итерирует по его индексам.ПрефиксКлюча добавляется текущий ключ или индекс в квадратных скобках ([Ключ] или [Индекс]). Для самого первого уровня (без ПрефиксКлюча) скобки не добавляются, чтобы получить name=..., а не [name]=....КодироватьСтроку(Значение, СпособКодированияСтроки.КодировкаURL).Массив СтрокаПараметров, а затем объединяются в одну строку с использованием разделителя & с помощью СтроковыеФункции.Объединить().После того как мы сформировали нужную строку тела запроса, нам необходимо правильно настроить и отправить HTTP-запрос в 1С.
СформироватьURLКодированнуюСтроку с подготовленными данными.
СтрокаТелаЗапроса = СформироватьURLКодированнуюСтроку(ДанныеЗапроса);
// СтрокаТелаЗапроса будет иметь вид: "name=имя&type_id=1&massive1[color][2]=желтый&massive1[color][3]=зеленый" (после кодирования значений)
Content-Type в значение application/x-www-form-urlencoded. Это сообщает серверу, какой тип данных он должен ожидать в теле запроса.
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
HTTPЗапрос и HTTPСоединение для отправки запроса.
// Шаг 3: Создание и отправка HTTP-запроса
ЗапросВ = Новый HTTPЗапрос;
ЗапросВ.Заголовки = Заголовки; // Присваиваем сформированные заголовки
// Устанавливаем тело запроса из строки, указывая кодировку
// Важно: для латиницы и цифр можно использовать КодировкаТекста.ANSI,
// но для кириллицы лучше КодировкаТекста.UTF8
ЗапросВ.УстановитьТелоИзСтроки(СтрокаТелаЗапроса, КодировкаТекста.UTF8);
// Пример URL-адреса и порта для соединения (замените на свои)
ИмяСервера = "example.com";
ПортСервера = 443; // Для HTTPS
// Создаем защищенное соединение для HTTPS
Соединение = Новый HTTPСоединение(ИмяСервера, ПортСервера, , , , , Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено));
Попытка
Ответ = Соединение.Отправить(ЗапросВ);
Если Ответ.КодСостояния = 200 Тогда
Сообщить("Запрос успешно отправлен. Ответ: " + Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
Иначе
Сообщить("Ошибка при отправке запроса. Код состояния: " + Ответ.КодСостояния);
Сообщить("Текст ошибки: " + Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
КонецЕсли;
Исключение
Сообщить("Произошла ошибка при выполнении HTTP-запроса: " + ОписаниеОшибки());
КонецПопытки;
Обратите внимание, что для HTTPS-соединений необходимо использовать объект ЗащищенноеСоединениеOpenSSL. Если ваш сервис работает по HTTP, то достаточно Новый HTTPСоединение(...) без последнего параметра.
СформироватьURLКодированнуюСтроку обрабатывает Соответствия и Массивы. Если в ваших данных могут встречаться другие сложные типы (например, ФиксированноеСоответствие или ФиксированныйМассив), их также потребуется соответствующим образом обработать или предварительно преобразовать.massive1[color][]=желтый&massive1[color][]=зеленый), то в функции нужно будет скорректировать формирование ключа для массива: НовыйПрефикс = ПрефиксКлюча + "[]" вместо ПрефиксКлюча + "[" + Индекс + "]". В нашем случае, с ключами 2 и 3, текущая реализация подходит.Таким образом, хотя 1С не предоставляет готовой "коробки" для сериализации сложных структур в application/x-www-form-urlencoded, мы можем эффективно решить эту задачу, написав собственную рекурсивную функцию. Этот подход является гибким и позволяет адаптироваться к специфическим требованиям различных веб-сервисов.