Как исправить ошибку 400 при отправке XML с вложенным CDATA через HTTPСоединение в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешними веб-сервисами (например, системами электронных фактур или государственными порталами) разработчики часто сталкиваются с ситуацией, когда стандартный объект HTTPСоединение возвращает ошибку 400 Bad Request. Особенно часто это происходит при передаче сложных XML-структур, где один из атрибутов или узлов содержит вложенный XML, обернутый в секцию ![CDATA[ ... ]].

Интересно, что тот же самый запрос, отправленный через COM-объект MSXML2.XMLHTTP, может отрабатывать корректно. Это наводит на мысль о нюансах реализации протокола HTTP в самой платформе 1С. В данной статье мы разберем, почему возникает эта проблема, проанализируем влияние кодировок и специальных символов, а также составим пошаговую инструкцию по правильной настройке HTTPЗапроса.

Причина ошибки 400: Почему сервер не понимает запрос

Код состояния 400 Bad Request означает, что сервер не смог обработать запрос из-за некорректного синтаксиса. При работе с XML в 1С основными «виновниками» этой ошибки являются:

  1. Наличие BOM (Byte Order Mark) — невидимые символы в начале строки, которые 1С может добавлять автоматически. Многие парсеры XML на стороне сервера воспринимают их как мусор перед декларацией ?xml.
  2. Несоответствие кодировки — если в заголовке запроса указана одна кодировка (например, UTF-8), а тело сформировано в другой (например, Windows-1251), сервер прервет обработку.
  3. Неявные заголовки — в отличие от браузеров или специализированных библиотек, HTTPСоединение в 1С требует явного указания Content-Type.
  4. Специфика CDATA — наличие вложенных структур XML внутри секции CDATA может приводить к ошибкам, если символы внутри секции не соответствуют ожиданиям парсера или если сама секция закрывается преждевременно.

Разбираем решение через управление телом запроса

Проанализируем ситуацию, описанную в практике: замена кодировки на ANSI при установке тела запроса помогла решить проблему. Рассмотрим, как правильно использовать метод УстановитьТелоИзСтроки для исключения ошибок синтаксиса.

Синтаксис метода выглядит следующим образом:

УстановитьТелоИзСтроки(<ТелоКакСтрока>, <Кодировка>, <ИспользоватьBOM>)

Разберем по шагам правильный алгоритм формирования запроса:

Шаг 1. Отключение BOM. Это критически важный момент. Чтобы веб-сервер не «споткнулся» о начальные байты строки, мы должны явно указать 1С не использовать BOM. Используем для этого системное перечисление ИспользованиеByteOrderMark.НеИспользовать.

Шаг 2. Выбор правильной кодировки. Хотя стандартом для XML является UTF-8, некоторые сервера (особенно работающие на устаревших стеках технологий или настроенные под специфические региональные стандарты) лучше принимают ANSI (Windows-1251). Если ваш запрос с UTF-8 не проходит, попробуйте явно указать КодировкаТекста.ANSI.

Посмотрим на пример кода, который решает проблему:


// Формируем текст XML запроса
ТекстXML = "<Root><Data><![CDATA[" + ВложенныйXML + "]]></Data></Root>";

// Подготавливаем запрос
Запрос = Новый HTTPЗапрос("/api/efactura");
Запрос.Заголовки.Вставить("Content-Type", "application/xml; charset=utf-8");

// Устанавливаем тело запроса с явным указанием параметров
// Используем ANSI и отключаем BOM
Запрос.УстановитьТелоИзСтроки(ТекстXML, КодировкаТекста.ANSI, ИспользованиеByteOrderMark.НеИспользовать);

// Выполняем отправку
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Почему COM-объект MSXML2.XMLHTTP работал иначе?

Многие разработчики задаются вопросом: почему старый метод через COMОбъект работает «из коробки»? Ответ кроется в том, что MSXML2.XMLHTTP является оберткой над системными библиотеками Windows (WinHTTP/WinInet). Эти библиотеки автоматически управляют многими низкоуровневыми аспектами:

В 1С при использовании HTTPСоединение мы работаем на более низком уровне и должны контролировать каждый байт передаваемой информации. Поэтому ручная настройка кодировки и отключение BOM становятся обязательными при работе со строгими XML-парсерами.

Рекомендации по работе с вложенными XML (CDATA)

Если в вашем XML-запросе есть вложенный XML внутри CDATA, проанализируем ситуацию с точки зрения корректности данных:

  1. Экранирование закрывающих тегов. Если во вложенном XML случайно встретится комбинация символов ]]>, внешняя секция CDATA будет закрыта раньше времени. Это гарантированно приведет к ошибке 400. Убедитесь, что данные внутри CDATA не содержат этой последовательности.
  2. Использование ЗаписиXML. Вместо простой конкатенации строк (склеивания через "+"), лучше использовать объект ЗаписьXML. Он автоматически позаботится о правильном формировании секций CDATA и спецсимволов.

Рассмотрим пример правильного формирования XML с вложенной секцией:


Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку();
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("Request");

Запись.ЗаписатьНачалоЭлемента("Content");
// Записываем вложенный XML как текст в секции CDATA
Запись.ЗаписатьСекциюCDATA(ВложенныйXMLТекст); 
Запись.ЗаписатьКонецЭлемента(); // Content

Запись.ЗаписатьКонецЭлемента(); // Request
РезультатXML = Запись.Закрыть();

Переход на современные методы платформы

Метод ОтправитьДляОбработки считается устаревшим в современных версиях платформы 8.3. Для более стабильной работы и детального контроля рекомендуется использовать метод ВызватьHTTPМетод.

Разберем пример современного подхода:


// Создаем соединение с поддержкой OpenSSL
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение("example.com", 443, , , , , Защита);

// Создаем запрос
Запрос = Новый HTTPЗапрос("/api/v1/data");
Запрос.Заголовки.Вставить("Content-Type", "text/xml; charset=windows-1251");

// Устанавливаем тело без BOM
Запрос.УстановитьТелоИзСтроки(ТекстЗапроса, "windows-1251", ИспользованиеByteOrderMark.НеИспользовать);

// Вызываем метод POST
Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос);

Если Ответ.КодСостояния <> 200 Тогда
    Сообщить("Ошибка запроса: " + Ответ.КодСостояния);
    Сообщить(Ответ.ПолучитьТелоКакСтроку());
КонецЕсли;

Резюме: Если вы получаете ошибку 400 при отправке XML, первым делом попробуйте явно отключить BOM и поэкспериментируйте с кодировками (UTF-8 vs ANSI). В большинстве случаев проблема кроется именно в этих невидимых байтах, которые 1С добавляет к строке по умолчанию.

← На главную