При интеграции 1С с внешними REST API через HTTPS часто возникает задача отправки данных в формате form-data. Это может быть необходимо для передачи логина и пароля, других ключевых параметров или даже файлов. Однако, как показывает практика (для начинающих разработчиков будет полезен интерактивный обучающий курс по работе с HTTP-запросами), некорректное формирование такого запроса из 1С может приводить к ошибкам, например, к ошибке 403 (Forbidden) с сообщением о недопустимых параметрах.
В этой статье мы подробно разберем, как правильно сформировать и отправить HTTPS REST запрос с параметрами form-data из 1С, используя объекты HTTPСоединение и HTTPЗапрос. Подобные механизмы лежат в основе сложных систем, таких как подсистема импорта задач из Jira в 1С через REST API, где требуется надежный обмен данными.
Предположим, мы отправляем запрос к внешнему API, передавая параметры user и pass в теле запроса. На стороне сервера ожидаются параметры с именами "user" и "pass", но вместо этого сервер получает их как "REQUEST_ARGS.user" и "REQUEST_ARGS.pass". Это явный признак того, что сервер не может правильно распарсить тело запроса, то есть формат, в котором мы передали form-data, оказался некорректным.
Исходный код запроса может выглядеть так:
//Попытка
//Создаем HTTPS соединение
АдресСервера = "api2.krs.ru";
РесурсНаСервере = "/api/rest/specific";
HTTPСоединение = Новый HTTPСоединение(АдресСервера,,,,,,Новый ЗащищенноеСоединениеOpenSSL);
//...
Если НЕ HTTPСоединение = Неопределено Тогда
//Параметры Post запроса
мПараметры = Новый Соответствие;
мПараметры.Вставить("user" , "admin"); //Логин
мПараметры.Вставить("pass" , "12345"); //Пароль
мПараметры.Вставить("date_from", "20250611"); //С даты (YYYYMMDD)
мПараметры.Вставить("date_to" , "20250615"); //По дату (YYYYMMDD)
// Преобразуем параметры в строку form-data
Разделитель = СтрЗаменить(Новый УникальныйИдентификатор, "-", ""); // Ошибка тут!
ТипКонтента = СтрШаблон("multipart/form-data; boundary=%1", Разделитель);
ПараметрыСтрокой = "";
Для Каждого Параметр Из мПараметры Цикл
ПараметрыСтрокой = ПараметрыСтрокой + Разделитель + Параметр.Ключ + "=" + Параметр.Значение;
КонецЦикла;
HTTPЗапрос = Новый HTTPЗапрос;
HTTPЗапрос.АдресРесурса = РесурсНаСервере;
HTTPЗапрос.Заголовки.Вставить("Content-Type", ТипКонтента);
HTTPЗапрос.УстановитьТелоИзСтроки(ПараметрыСтрокой, "UTF-8"); // Устанавливаем тело запроса
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
//...
КонецЕсли;
В этом примере есть несколько критических ошибок, которые приводят к неверному формированию multipart/form-data. Основные из них:
multipart/form-data: Для этого типа контента требуется строгий формат с разделителями (boundary), заголовками для каждой части (Content-Disposition) и пустыми строками. Простое склеивание параметров в строку с разделителем недостаточно.multipart/form-data, особенно если планируется отправлять файлы или бинарные данные, крайне желательно формировать тело запроса как двоичные данные. Метод УстановитьТелоИзСтроки() может быть неподходящим или менее гибким.Прежде чем погружаться в код 1С (поможет пошаговая отладка и вычисление выражений в 1С), рассмотрим незаменимые инструменты, которые помогут нам в отладке любых HTTP-запросов:
Postman — это мощный инструмент для тестирования, разработки и документирования API. Он позволяет легко формировать HTTP-запросы любой сложности, включая form-data, отправлять их и анализировать ответы. Если ваш запрос успешно работает в Postman, это означает, что проблема не в API сервера, а в том, как 1С формирует запрос.
Fiddler — это HTTP/HTTPS прокси-сервер, который перехватывает весь веб-трафик с вашего компьютера. Он позволяет увидеть, какие именно байты отправляет 1С на сервер, включая все заголовки и тело запроса. Это критически важно, чтобы сравнить "рабочий" запрос из Postman с "нерабочим" запросом из 1С.
Для корректной отправки multipart/form-data в 1С нам необходимо вручную сформировать тело запроса, используя объекты ПотокВПамяти и ЗаписьДанных. Это позволит нам точно контролировать структуру данных, разделители (boundary) и кодировку.
Формат multipart/form-data предполагает разделение каждого параметра или файла на отдельные части с помощью специального разделителя (boundary). Каждая часть начинается с разделителя, затем содержит заголовки (например, Content-Disposition, name, filename, Content-Type), за которыми следуют пустая строка и само значение параметра или содержимое файла. В конце всего тела запроса добавляется финальный разделитель.
Важные моменты:
--).--).Рассмотрим процедуру, которая инкапсулирует логику формирования тела multipart/form-data. Эта процедура будет принимать объект HTTPЗапрос и набор параметров, а затем устанавливать тело запроса и необходимые заголовки.
Для создания динамического разделителя (boundary) мы будем использовать Новый УникальныйИдентификатор, удаляя дефисы. Этот разделитель должен быть уникальным, чтобы не встретиться в самих данных.
Процедура ВставитьПараметрыВЗапрос(АдресСервера, ЗапросHTTP, UserId, api_key, date_from, date_to)
Разделитель = СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
ПотокВПамяти = Новый ПотокВПамяти;
ЗаписьДанных = Новый ЗаписьДанных(ПотокВПамяти); // По умолчанию UTF-8
// Добавляем параметр "user"
ЗаписьДанных.ЗаписатьСтроку("--"+Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""user""");
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка
ЗаписьДанных.ЗаписатьСтроку(СокрЛП(UserId));
// Добавляем параметр "pass" (или api_key)
ЗаписьДанных.ЗаписатьСтроку("--"+Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""pass"""); // Или "api_key" в зависимости от API
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка
ЗаписьДанных.ЗаписатьСтроку(СокрЛП(api_key));
// Добавляем параметр "date_from"
ЗаписьДанных.ЗаписатьСтроку("--"+Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""date_from""");
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка
ЗаписьДанных.ЗаписатьСтроку(СокрЛП(date_from));
// Добавляем параметр "date_to"
ЗаписьДанных.ЗаписатьСтроку("--"+Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""date_to""");
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка
ЗаписьДанных.ЗаписатьСтроку(СокрЛП(date_to));
// Завершающий разделитель
ЗаписьДанных.ЗаписатьСтроку("--"+Разделитель+"--");
ЗаписьДанных.Закрыть();
// Получаем тело запроса в виде двоичных данных
ДвоичныеДанныеТело = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные;
ЗапросHTTP.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТело);
// Устанавливаем заголовки
ТипКонтента = СтрШаблон("multipart/form-data; boundary=%1", Разделитель);
ЗапросHTTP.Заголовки.Вставить("Content-Type" , ТипКонтента);
КонецПроцедуры
Разберем по шагам ключевые моменты этой процедуры:
Content-Disposition: form-data и имя поля. Это стандарт, который понимают все современные API.Теперь соберем все вместе. Данный подход часто применяется в специализированных интеграциях, таких как получение данных о контрагенте по API, где точность формирования запроса определяет успех операции.
// ... код подготовки данных ...
Если НЕ HTTPСоединение = Неопределено Тогда
Пока Выборка.Следующий Цикл
// ... подготовка UserId и api_key ...
Попытка
HTTPЗапрос = Новый HTTPЗапрос(РесурсНаСервере);
ВставитьПараметрыВЗапрос(АдресСервера, HTTPЗапрос, UserId, api_key, мСДаты, мПоДату);
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
// ... обработка ответа ...
Исключение
// ... обработка ошибок ...
КонецПопытки;
КонецЦикла;
КонецЕсли;
Если API не требует передачи файлов и принимает простые параметры ключ-значение, то более простым вариантом может быть использование Content-Type: application/x-www-form-urlencoded. Этот способ значительно проще в реализации, но не всегда подходит, особенно если API строго ожидает multipart/form-data.
Пример такого запроса:
//...
ПараметрыСтрокой = "";
Для Каждого Параметр Из мПараметры Цикл
Если НЕ ПустаяСтрока(ПараметрыСтрокой) Тогда
ПараметрыСтрокой = ПараметрыСтрокой + "&";
КонецЕсли;
ПараметрыСтрокой = ПараметрыСтрокой + Параметр.Ключ + "=" + КодироватьСтроку(Параметр.Значение, "UTF-8", "URL");
КонецЦикла;
HTTPЗапрос = Новый HTTPЗапрос(РесурсНаСервере);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
HTTPЗапрос.УстановитьТелоИзСтроки(ПараметрыСтрокой, "UTF-8");
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
//...
ЗаписьДанных по умолчанию используется UTF-8, что является хорошим стандартом.Для ускорения разработки и минимизации ошибок при создании собственных интерфейсов можно использовать универсальный модуль с процедурами для быстрой разработки HTTP-сервисов.
Следуя этим рекомендациям и используя инструменты отладки, вы сможете эффективно решить проблемы с отправкой HTTPS REST запросов с параметрами form-data из 1С и успешно интегрировать вашу систему с внешними сервисами.