При интеграции 1С с внешними веб-сервисами, интернет-магазинами, государственными информационными системами или сторонними API разработчики постоянно сталкиваются с необходимостью отправки POST-запросов. В отличие от GET-запросов, где параметры чаще всего передаются непосредственно в строке адреса (URL), POST-запросы предполагают передачу данных в теле запроса (Request Body). Это могут быть структурированные данные JSON/XML, бинарные файлы или сложные формы формата multipart/form-data.
В этой статье мы подробно разберем все аспекты работы с POST-запросами в 1С. Мы изучим как базовые сценарии (передачу JSON-параметров и файлов), так и профессиональные подходы, актуальные для современных версий платформы 1С:Предприятие 8.3, включая работу с асинхронными методами и потоками данных.
Прежде чем наполнять запрос данными, нам необходимо правильно настроить базовые объекты: HTTPСоединение и HTTPЗапрос. Для обеспечения безопасности в современном веб-пространстве практически всегда используется защищенное соединение (HTTPS), требующее использования объекта ЗащищенноеСоединениеOpenSSL.
Рассмотрим пример инициализации базовых объектов и установки заголовков:
// Создаем защищенное соединение для работы по протоколу HTTPS
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение("api.myservice.ru", 443, , , , , ЗащищенноеСоединение);
// Определяем заголовки запроса
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json; charset=UTF-8");
Заголовки.Вставить("Accept", "application/json");
// Создаем объект запроса с указанием относительного пути (URI) и заголовков
Запрос = Новый HTTPЗапрос("/api/v1/users", Заголовки);
Обратите внимание на заголовок Content-Type. Он сообщает серверу, в каком формате мы передаем данные в теле запроса. В данном примере мы указали application/json, что является стандартом де-факто для современных REST API.
Для передачи параметров (например, ID пользователя, статуса, настроек) в теле запроса используется метод УстановитьТелоИзСтроки(). Однако ручное формирование JSON-строки чревато синтаксическими ошибками. Правильным подходом является сериализация объектов 1С (таких как Структура или Соответствие) с помощью встроенных механизмов работы с JSON.
Разберем правильный и надежный способ подготовки параметров:
// Формируем параметры запроса в виде привычной структуры 1С
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("id", 10254);
ПараметрыЗапроса.Вставить("status", "active");
ПараметрыЗапроса.Вставить("email", "user@example.com");
// Сериализуем структуру в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
СтрокаТелаЗапроса = ЗаписьJSON.Закрыть();
// Устанавливаем сформированную строку в тело запроса
Запрос.УстановитьТелоИзСтроки(СтрокаТелаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Важная деталь: При вызове метода УстановитьТелоИзСтроки крайне важно использовать параметр ИспользованиеByteOrderMark.НеИспользовать. Если этого не сделать, 1С может добавить маркер последовательности байтов (BOM) в начало строки, из-за чего многие веб-серверы не смогут корректно распарсить входящий JSON и вернут ошибку HTTP 400 Bad Request.
Часто перед разработчиком встает задача отправить файл (изображение, PDF-документ, XML-выгрузку) на сервер. В платформе 1С реализовано несколько способов решения этой задачи в зависимости от размера передаваемых файлов.
Если файл имеет большой размер (от нескольких мегабайт до гигабайт), загрузка его целиком в оперативную память может привести к перерасходу ресурсов сервера 1С или аварийному завершению работы процесса. Метод УстановитьИмяФайлаТела() позволяет платформе считывать данные напрямую с жесткого диска и порционно транслировать их в сетевой сокет.
ПутьКФайлу = "C:\temp\huge_report.pdf";
// Указываем платформе путь к файлу, который будет отправлен в теле запроса
Запрос.УстановитьИмяФайлаТела(ПутьКФайлу);
// В заголовках запроса рекомендуется указать соответствующий MIME-тип
Запрос.Заголовки.Вставить("Content-Type", "application/pdf");
Если файл небольшой и вы уже работаете с ним в памяти в виде объекта ДвоичныеДанные, можно использовать метод УстановитьТелоИзДвоичныхДанных():
ДвоичныеДанныеФайла = Новый ДвоичныеДанные("C:\temp\small_icon.png");
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеФайла);
Запрос.Заголовки.Вставить("Content-Type", "image/png");
Бывают ситуации, когда веб-сервис требует передать и текстовые параметры (например, ID папки, описание файла), и сам файл в рамках одного POST-запроса. Стандартный JSON в этом случае не подходит — используется кодирование multipart/form-data. Этот формат предполагает разделение данных специальной уникальной границей (boundary).
Начиная с версии 8.3.9, формировать такое тело запроса удобнее всего в оперативной памяти через потоки данных, избегая создания лишних временных файлов на диске:
// Определяем уникальный разделитель (boundary)
Разделитель = "----1CBoundary" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
// Указываем тип контента с границей в заголовках запроса
Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
// Создаем поток в памяти для формирования тела запроса
ПотокТела = Новый ПотокВПамяти;
ЗаписьДанных = Новый ЗаписьДанных(ПотокТела, КодировкаТекста.UTF8);
// 1. Записываем текстовый параметр "folder_id"
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""folder_id""");
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка перед значением
ЗаписьДанных.ЗаписатьСтроку("9985"); // Значение параметра
// 2. Добавляем секцию для файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные("C:\temp\document.docx");
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""document.docx""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document");
ЗаписьДанных.ЗаписатьСтроку(""); // Обязательная пустая строка перед бинарными данными
// Сбрасываем буфер записи текста перед записью бинарных данных
ЗаписьДанных.СброситьБуфер();
// Записываем бинарные данные файла в поток тела запроса
ПотокТела.Записать(ДвоичныеДанныеФайла);
// Завершаем тело запроса финальной границей
ЗаписьДанных.ЗаписатьСтроку("");
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--");
ЗаписьДанных.СброситьБуфер();
// Получаем результирующие двоичные данные из потока и помещаем их в запрос
ДвоичныеДанныеТела = ПотокТела.ЗакрытьИПолучитьДвоичныеДанные();
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТела);
После того как тело запроса полностью сформировано, его необходимо отправить на сервер. Исторически для отправки POST-запросов применялся метод ОтправитьДляОбработки(). Однако в современной разработке на платформе 1С произошли важные изменения, о которых обязан знать каждый разработчик.
ОтправитьДляОбработки или Записать) рекомендуется использовать метод ВызватьHTTPМетод(). Он делает код более понятным, так как тип HTTP-метода ("POST", "PUT", "DELETE", "PATCH") явно передается в качестве первого аргумента.
Попытка
// Используем универсальный метод ВызватьHTTPМетод вместо ОтправитьДляОбработки
Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос);
Если Ответ.КодСостояния = 200 Или Ответ.КодСостояния = 201 Тогда
Сообщить("Данные успешно отправлены! Ответ сервера: " + Ответ.ПолучитьТелоКакСтроку());
Иначе
ВызватьИсключение "Сервер вернул код ошибки: " + Ответ.КодСостояния;
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("Интеграция.ВыгрузкаДанных", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось связаться с сервером. Подробности записаны в журнал регистрации.";
КонецПопытки;
&НаКлиенте
Асинх Процедура ОтправитьДанныеНаКлиенте()
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение("api.myservice.ru", 443, , , , , ЗащищенноеСоединение);
Запрос = Новый HTTPЗапрос("/api/v1/data");
Запрос.УстановитьТелоИзСтроки("{""param"":""value""}", КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Попытка
// Асинхронное ожидание выполнения сетевой операции без замораживания интерфейса
Ответ = Ждать Соединение.ВызватьHTTPМетодАсинх("POST", Запрос);
Если Ответ.КодСостояния = 200 Тогда
ПоказатьПредупреждение(, "Данные успешно отправлены!");
КонецЕсли;
Исключение
ПоказатьПредупреждение(, "Произошла ошибка при отправке данных: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Использование конструкции Ждать и директивы Асинх позволяет писать лаконичный и читаемый код, который при этом работает асинхронно, обеспечивая плавность работы интерфейса вашей конфигурации 1С.