При интеграции 1С с внешними системами, особенно написанными на языке C# (WCF) или работающими через СМЭВ 3, разработчики часто сталкиваются с необходимостью передачи специфических и сложных заголовков HTTP-запроса. Обычной строки в теле запроса недостаточно — сервер ожидает строго определенную структуру метаданных. Разберем пошагово, как правильно настроить заголовки, сформировать тело запроса и избежать распространенных ошибок вроде Incoming message is not xml message.
В платформе 1С для передачи заголовков в объекте HTTPЗапрос используется коллекция Соответствие. Каждый элемент этой коллекции представляет собой пару Ключ (имя заголовка) и Значение (содержимое заголовка). Рассмотрим, как это реализовать в коде.
Проанализируем пример создания базовых заголовков для SOAP-сервиса:
Заголовки = Новый Соответствие;
// Указываем тип контента. Обратите внимание на использование двойных кавычек внутри строки.
Заголовки.Вставить("Content-Type", "text/xml;charset=UTF-8");
// Если сервер требует SOAPAction (характерно для SOAP 1.1)
Заголовки.Вставить("SOAPAction", """urn:SendRequest""");
// Дополнительные параметры, если они требуются API
Заголовки.Вставить("Accept-Encoding", "gzip,deflate");
Важный нюанс: если значение заголовка должно содержать кавычки (например, в SOAPAction), в языке 1С они экранируются путем удвоения: """Значение""" превратится в "Значение" при отправке запроса.
Если вы столкнулись с технологией MTOM (Message Transmission Optimization Mechanism), заголовки становятся значительно сложнее. В этом случае заголовок Content-Type содержит множество параметров, включая boundary (границу) и type. Проанализируем, как правильно собрать такую строку.
Рассмотрим пример формирования заголовка для работы с XOP/MTOM:
Граница = "----=_Part_" + Строка(Новый УникальныйИдентификатор());
ЗаголовокТип = "multipart/related; type=""application/xop+xml""; start=""<rootpart>""; start-info=""text/xml""; boundary=""" + Граница + """";
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", ЗаголовокТип);
Заголовки.Вставить("MIME-Version", "1.0");
В данном случае мы вручную конструируем строку типа контента. Помните, что параметр boundary должен быть уникальным для каждого запроса, чтобы сервер мог корректно разделить части сообщения.
Часто программисты 1С сталкиваются с тем, что заголовки заданы верно, а сервер все равно возвращает ошибку о невалидном XML. Выясним причину. При использовании метода УстановитьТелоИзСтроки 1С по умолчанию может добавлять BOM (Byte Order Mark) — невидимые символы в начале строки, которые указывают на кодировку UTF-8.
Многие современные веб-сервисы (особенно на .NET) не умеют обрабатывать BOM и воспринимают его как мусор перед началом XML-документа. Чтобы избежать этого, выполним следующие шаги:
ИспользоватьBOM.Нет при установке тела.КодировкаТекста.UTF8.Посмотрим на правильный пример установки тела запроса:
ТекстXML = "<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">...</soapenv:Envelope>";
ЗапросHTTP = Новый HTTPЗапрос(АдресРесурса, Заголовки);
// Устанавливаем тело без BOM
ЗапросHTTP.УстановитьТелоИзСтроки(ТекстXML, КодировкаТекста.UTF8, ИспользоватьBOM.Нет);
Иногда заголовков недостаточно, и параметры нужно передать непосредственно в строке адреса (GET или POST запросы). Разберем, как это сделать правильно, не нарушая структуру URL.
Рассмотрим функцию, которая добавляет параметры к адресу:
Функция СформироватьАдресСПараметрами(БазовыйАдрес, Параметры)
Результат = БазовыйАдрес;
ПервыйПараметр = Истина;
Для Каждого ТекПараметр Из Параметры Цикл
Разделитель = ?(ПервыйПараметр, "?", "&");
Результат = Результат + Разделитель + ТекПараметр.Ключ + "=" + ТекПараметр.Значение;
ПервыйПараметр = Ложь;
КонецЦикла;
Возврат Результат;
КонецФункции
После того как заголовки подготовлены в объекте Соответствие, а тело запроса сформировано, необходимо выполнить саму отправку. Рассмотрим полный цикл работы с объектом HTTPСоединение.
// Настройка защищенного соединения, если используется HTTPS
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("example.com", 443, , , , 30, Защита);
// Создание запроса с заголовками
Запрос = Новый HTTPЗапрос("/api/v1/method", Заголовки);
Запрос.УстановитьТелоИзСтроки(ТекстЗапроса, КодировкаТекста.UTF8, ИспользоватьBOM.Нет);
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Сообщить("Код состояния: " + Ответ.КодСостояния);
ТекстОтвета = Ответ.ПолучитьТелоКакСтроку();
Исключение
Сообщить("Ошибка при отправке запроса: " + ОписаниеОшибки());
КонецПопытки;
В некоторых случаях стандартный объект HTTPСоединение может ограничивать разработчика (например, при работе со специфическими сертификатами или нестандартными методами аутентификации). В таких ситуациях проанализируем возможность использования COM-объекта WinHttp.WinHttpRequest.5.1.
Этот метод позволяет более гибко управлять заголовками:
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open("POST", "https://smev3-n0.test.gosuslugi.ru:7500", Ложь);
WinHttp.SetRequestHeader("Content-Type", "text/xml;charset=UTF-8");
WinHttp.SetRequestHeader("SOAPAction", """urn:SendRequest""");
WinHttp.Send(ТекстXML);
Статус = WinHttp.Status;
ОтветТекст = WinHttp.ResponseText;
Подводя итог, выделим ключевые правила работы со сложными заголовками в 1С:
Content-Type вместо content-type).Content-Type в консоль, чтобы сравнить её с примером из документации или SoapUI.Соблюдение этих правил позволит вам успешно интегрировать 1С с любыми сложными внешними сервисами, обеспечивая надежный обмен данными.