При интеграции устаревших систем на платформе 1С:Предприятие 7.7 с современными веб-порталами (например, личным кабинетом дистрибьютора «Русскарт») разработчики часто сталкиваются с необходимостью отправки файлов или структурированных XML-данных. Наиболее популярным методом отправки файлов через веб-формы является протокол HTTP POST с кодированием типа multipart/form-data.
В этой статье мы подробно разберем, как правильно сформировать тело такого запроса, настроить границы разделов (boundary), корректно установить HTTP-заголовки, а также решить сопутствующие проблемы с кодировкой UTF-8 и поддержкой защищенного протокола HTTPS (TLS 1.2) в среде 1С 7.7.
Когда мы отправляем обычный POST-запрос, данные передаются в виде простых пар "ключ=значение". Однако формат multipart/form-data устроен сложнее. Он позволяет передавать данные несколькими независимыми блоками в рамках одного запроса. Каждый блок имеет свои собственные заголовки (например, имя поля Content-Disposition), за которыми следует пустая строка-разделитель, а затем — само значение поля или содержимое файла.
Для разделения этих блоков используется специальный уникальный набор символов — Boundary (граница). Сервер определяет начало и конец каждого параметра именно по этой границе. Если нарушить разметку (не поставить пустую строку, забыть дефисы перед границей или перепутать разделители строк), веб-сервер выдаст ошибку (например, сообщит, что обязательный параметр «Логин» не передан).
Проанализируем структуру тела запроса, которую ожидает получить принимающий шлюз:
--ГраницаРаздела
Content-Disposition: form-data; name="login"
МойЛогин
--ГраницаРаздела
Content-Disposition: form-data; name="pswd"
МойПароль
--ГраницаРаздела
Content-Disposition: form-data; name="xml"
<?xml version="1.0" encoding="utf-8"?><root>...данные...</root>
--ГраницаРаздела--
Обратите внимание: перед каждой границей внутри тела запроса обязательно ставятся два дефиса --, а финальная граница закрывается двумя дефисами с обеих сторон: --ГраницаРаздела--.
Граница должна быть уникальной строкой, которая гарантированно не встретится внутри передаваемых данных (внутри логина, пароля или самого XML-файла). Лучше всего использовать GUID. Сделать это в 1С 7.7 можно при помощи стандартной библиотеки v7plus.dll (объект AddIn.V7SysInfo) или через 1cpp.dll.
Рассмотрим пример генерации уникальной границы на основе GUID через стандартную компоненту:
Инфо = СоздатьОбъект("AddIn.V7SysInfo");
ГлобальноУникальныйИдентификатор = Инфо.СоздатьGUID();
// Уберем лишние дефисы из GUID для простоты
Boundary = СтрЗаменить(Строка(ГлобальноУникальныйИдентификатор), "-", "");
Если на сервере не зарегистрирована библиотека v7plus.dll, можно воспользоваться стандартным системным объектом операционной системы Windows:
TypeLib = CreateObject("Scriptlet.TypeLib");
NewGUID = TypeLib.Guid();
Boundary = Сред(NewGUID, 2, 36); // Извлекаем чистый GUID без фигурных скобок
Boundary = СтрЗаменить(Boundary, "-", "");
Важнейшее правило формирования блоков multipart/form-data: заголовки каждого блока должны отделяться от его значения строго пустой строкой. В качестве символа перевода строки необходимо использовать пару символов возврата каретки и перевода строки — CRLF (в 1С 7.7 это системная константа РазделительСтрок или сочетание Симв(13) + Симв(10)).
Соберем тело запроса по шагам, аккуратно расставляя разделители:
ТекстЗапроса = "";
// Блок 1: Передача Логина
ТекстЗапроса = ТекстЗапроса + "--" + Boundary + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + "Content-Disposition: form-data; name=""login""" + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + РазделительСтрок; // Пустая строка перед значением!
ТекстЗапроса = ТекстЗапроса + СокрЛП(Login) + РазделительСтрок;
// Блок 2: Передача Пароля
ТекстЗапроса = ТекстЗапроса + "--" + Boundary + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + "Content-Disposition: form-data; name=""pswd""" + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + РазделительСтрок; // Пустая строка перед значением!
ТекстЗапроса = ТекстЗапроса + СокрЛП(Password) + РазделительСтрок;
// Блок 3: Передача XML-документа
ТекстЗапроса = ТекстЗапроса + "--" + Boundary + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + "Content-Disposition: form-data; name=""xml""" + РазделительСтрок;
ТекстЗапроса = ТекстЗапроса + РазделительСтрок; // Пустая строка перед значением!
ТекстЗапроса = ТекстЗапроса + СтрXML + РазделительСтрок;
// Финал: Закрываем тело запроса конечной границей
ТекстЗапроса = ТекстЗапроса + "--" + Boundary + "--" + РазделительСтрок;
Платформа 1С 7.7 работает в локальной кодировке Windows-1251 (ANSI). Если вы отправите собранную строку ТекстЗапроса напрямую, то кириллические символы в XML превратятся на сервере в нечитаемые «кракозябры». Современные веб-сервисы принимают строковые данные исключительно в кодировке UTF-8.
Для надежного преобразования сформированной строки в UTF-8 без использования внешних библиотек мы применим системный объект Windows ADODB.Stream. Он преобразует текст в бинарный массив (SafeArray), который будет корректно распознан HTTP-объектом при отправке.
Реализуем функцию перевода строки в бинарный UTF-8:
Функция ПреобразоватьВUtf8(СтрокаИсточник)
Stream = СоздатьОбъект("ADODB.Stream");
Stream.Type = 2; // Текстовый режим
Stream.Charset = "utf-8";
Stream.Open();
Stream.WriteText(СтрокаИсточник);
Stream.Position = 0;
Stream.Type = 1; // Переключаем в бинарный режим
// По желанию можно пропустить BOM (первые 3 байта), если сервер их не поддерживает
// Stream.Position = 3;
ДанныеUtf8 = Stream.Read();
Stream.Close();
Возврат ДанныеUtf8;
КонецФункции
Часто используемый объект Microsoft.XMLHTTP устарел и не всегда корректно поддерживает современные стандарты шифрования HTTPS (протоколы TLS 1.2 и TLS 1.3), которые сейчас в принудительном порядке включены на большинстве серверов. При попытке отправить запрос через него на адрес https://... вы можете получить ошибку соединения.
Для стабильной работы по защищенному каналу мы рекомендуем использовать более продвинутый системный HTTP-клиент — WinHttp.WinHttpRequest.5.1. Он позволяет принудительно активировать современные протоколы безопасности.
Объединим все элементы и выполним отправку:
// Готовим тело запроса в формате UTF-8
ТелоЗапросаБинарное = ПреобразоватьВUtf8(ТекстЗапроса);
// Создаем HTTP-клиент WinHttp
HTTP = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
// Инициализируем POST-запрос к нужному URL (например, к порталу Русскарт)
АдресПортала = "https://auto.russkart.com/distributor_document/";
HTTP.Open("POST", АдресПортала, 0); // 0 - синхронный режим ожидания ответа
// Включаем принудительную поддержку TLS 1.2 (код опции 9, значение опции 2048)
HTTP.Option(9, 2048);
// Настраиваем HTTP-заголовки
HTTP.SetRequestHeader("Host", "auto.russkart.com");
HTTP.SetRequestHeader("Cache-Control", "no-cache");
// Передаем правильный Content-Type с указанием сгенерированной нами границы
HTTP.SetRequestHeader("Content-Type", "multipart/form-data; boundary=" + Boundary);
// Отправляем подготовленный бинарный массив данных
HTTP.Send(ТелоЗапросаБинарное);
// Анализируем ответ сервера
КодРезультата = HTTP.Status;
ТекстОтвета = HTTP.ResponseText;
Если КодРезультата = 200 Тогда
Предупреждение("Данные успешно отправлены на портал! Ответ сервера: " + ТекстОтвета);
Иначе
Предупреждение("Ошибка отправки! Код ответа: " + КодРезультата + ". Описание: " + ТекстОтвета);
КонецЕсли;
Если развертывание скриптов ADODB.Stream вызывает сложности или на сервере действуют жесткие ограничения безопасности, можно пойти по пути, который часто рекомендуют технические специалисты веб-порталов. Это делегирование сборки и отправки пакета специализированной внешней консольной утилите cURL.
В этом сценарии из 1С 7.7 достаточно выгрузить XML-файл в кодировке UTF-8 на жесткий диск и выполнить вызов утилиты командной строки через Windows Shell. Утилита сама соберет multipart-пакет, проставит нужные границы и отправит данные по протоколу HTTPS:
// Предположим, XML сохранен по пути: C:\Russkart\upload.xml
ИмяФайлаXML = "C:\Russkart\upload.xml";
// Конструируем командную строку для cURL
// Параметр -F указывает curl автоматически сформировать блок multipart/form-data
КомандаRun = "curl.exe -X POST "
+ "-H ""Content-Type: multipart/form-data"" "
+ "-F ""login=" + СокрЛП(Login) + """ "
+ "-F ""pswd=" + СокрЛП(Password) + """ "
+ "-F ""xml=@" + ИмяФайлаXML + """ "
+ "https://auto.russkart.com/distributor_document/";
// Запускаем через Windows Shell скрытно, дожидаясь завершения
WshShell = СоздатьОбъект("WScript.Shell");
КодВозврата = WshShell.Run(КомандаRun, 0, 1);
Если КодВозврата = 0 Тогда
Сообщить("Выгрузка с помощью cURL завершена успешно.");
Иначе
Сообщить("Произошла ошибка при работе утилиты cURL. Код ошибки: " + КодВозврата);
КонецЕсли;
Использование WinHttp.WinHttpRequest.5.1 в сочетании с ADODB.Stream внутри кода 1С является наиболее красивым и бесшовным решением, поскольку оно не требует установки сторонних утилит и полностью контролирует процесс обмена данными "на лету". Выберите наиболее подходящий для вашей инфраструктуры метод и используйте его при построении интеграций.