Как правильно отправить XML-файл POST-запросом в 1С: разбор типичных ошибок и готовый шаблон

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

Интеграция систем 1С с внешними веб-сервисами, WMS-системами и REST API — одна из самых частых задач современного разработчика. Однако при отсутствии четкого технического задания (ТЗ) и жестких лимитах времени легко совершить архитектурные ошибки, которые приведут к зависанию системы, искажению данных или падению рабочего процесса сервера 1С. Особенно остро эти проблемы проявляются при передаче файлов больших объемов (от 10-50 МБ и выше).

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

Типичные ошибки при реализации HTTP-запросов в 1С

Прежде чем перейти к написанию готового шаблона, давайте детально проанализируем ошибки, которые часто встречаются в legacy-коде и на форумах разработчиков.

1. Ручной расчет заголовка Content-Length

Многие разработчики по старой привычке пытаются вручную вычислить размер отправляемого тела запроса и передать его в заголовках. Для этого они используют функцию СтрДлина(). Это приводит к критической ошибке:

Решение: В современной платформе 1С 8.3 при использовании объектов HTTPЗапрос ручной расчет длины больше не требуется. Платформа самостоятельно вычисляет точный размер в байтах при вызове методов УстановитьТелоИзСтроки() или УстановитьИмяФайлаТела().

2. Использование строк в памяти для больших XML (от 10 МБ до 70 МБ и более)

В попытках сделать решение «без лишних файлов на диске» разработчики нередко считывают XML-файл полностью в строку и передают ее через метод УстановитьТелоИзСтроки(). Рассмотрим, почему для файлов объемом 70 МБ это гарантированный крах:

Решение: Использовать дисковую потоковую передачу (стриминг). Данные записываются во временный файл, а затем подключаются к запросу через метод УстановитьИмяФайлаТела(). Платформа будет транслировать файл в сеть небольшими порциями, не перегружая RAM.

3. Игнорирование проблемы маркера BOM (Byte Order Mark)

По умолчанию при записи файлов в UTF-8 платформа 1С может добавлять в начало файла невидимую метку BOM (последовательность байтов EF BB BF). Большинство современных веб-серверов и сторонних WMS-систем не ожидают увидеть эти символы в начале XML-пакета и возвращают ошибку разбора формата (например, 400 Bad Request или SAXParseException).

Решение: При записи XML-файла или формировании строки необходимо явно указывать платформе не использовать маркер BOM.

4. Ошибки инициализации защищенного соединения (SSL/HTTPS)

При создании объекта HTTPСоединение разработчики часто путают параметры протокола. Например, указывают шестым параметром значение Истина (использовать защищенное соединение), но при этом обращаются к адресу по обычному незащищенному протоколу http:// на нестандартном порту (например, 7000). Это вызывает ошибку на этапе сетевого рукопожатия (Handshake).

Решение: Четко разделять параметры подключения. Если URL начинается с http://, защищенное соединение использовать нельзя, а порт нужно передавать отдельным вторым параметром конструктора.

5. Некорректный заголовок Content-Type

Отправляя XML-данные, разработчики нередко оставляют в заголовках значение application/json или забывают указать кодировку. Веб-сервер получателя не сможет корректно интерпретировать пришедший поток байтов без правильного указания типа содержимого.

Решение: Для XML-запросов всегда используйте заголовок application/xml; charset=utf-8 или text/xml; charset=utf-8.

Учитывая все перечисленные нюансы, давайте спроектируем правильную архитектуру отправки данных.

Пошаговый алгоритм реализации отправки XML

Рассмотрим детально каждый шаг решения задачи отправки крупного XML-файла во внешнюю систему.

Шаг 1. Формирование XML во временный файл без BOM

Для того чтобы не держать весь объем данных в оперативной памяти, мы будем записывать XML напрямую во временный файл на диске с помощью специализированного объекта ЗаписьXML. Мы обязательно отключим маркер BOM с помощью объекта ПараметрыЗаписиXML.

Шаг 2. Инициализация HTTP-соединения

Мы разберем исходный URL получателя. Например: http://192.168.20.12:7000/cwms/ws/NOM.DEV

Шаг 3. Подготовка HTTP-запроса

Мы создадим объект HTTPЗапрос, укажем правильный заголовок Content-Type и свяжем наш временный файл с телом запроса методом УстановитьИмяФайлаТела().

Шаг 4. Отправка и обработка ответа

Мы выполним отправку метода POST. Полученный ответ сервера мы прочитаем прямо в строку с помощью современного метода ПолучитьТелоКакСтроку(), избегая создания лишних файлов для ответа на диске. В конце обязательно удалим созданный временный файл тела запроса, чтобы не засорять жесткий диск сервера.

Оптимальный шаблон кода для платформы 1С 8.3

Ниже представлен готовый к использованию программный код, написанный по всем стандартам разработки под управляемые и обычные формы 1С v8.3:


&НаСервере
Процедура ОтправитьБольшойXMLНаСервер()
    
    // 1. Создаем временный файл для записи XML на диске (экономим RAM)
    ПутьКФайлуXML = ПолучитьИмяВременногоФайла("xml");
    
    ЗаписьXML = Новый ЗаписьXML;
    
    // Настраиваем параметры записи: кодировка UTF-8, БЕЗ добавления BOM
    ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", , Ложь); 
    ЗаписьXML.ОткрытьФайл(ПутьКФайлуXML, ПараметрыЗаписи);
    
    // Записываем структуру XML документа
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    ЗаписьXML.ЗаписатьНачалоЭлемента("Root");
    
    // Имитируем заполнение данными (в реальной задаче здесь будет ваш цикл)
    Для Индекс = 1 По 1000 Цикл
        ЗаписьXML.ЗаписатьНачалоЭлемента("Item");
        ЗаписьXML.ЗаписатьАтрибут("Id", Строка(Индекс));
        ЗаписьXML.ЗаписатьТекст("Тестовые данные для WMS системы № " + Строка(Индекс));
        ЗаписьXML.ЗаписатьКонецЭлемента();
    КонецЦикла;
    
    ЗаписьXML.ЗаписатьКонецЭлемента(); // Root
    ЗаписьXML.Закрыть();
    
    // 2. Параметры подключения к серверу (разбираем исходный URL)
    ИмяСервера = "192.168.20.12";
    Порт = 7000; 
    АдресРесурса = "/cwms/ws/NOM.DEV";
    Таймаут = 60; // Увеличиваем таймаут для больших файлов (в секундах)
    
    // Так как протокол HTTP (не HTTPS), защищенное соединение не требуется (Параметр 6 = Неопределено)
    Соединение = Новый HTTPСоединение(ИмяСервера, Порт, , , , Таймаут);
    
    // 3. Создаем и заполняем HTTP запрос
    Запрос = Новый HTTPЗапрос(АдресРесурса);
    
    // Указываем корректный тип контента для XML данных
    Запрос.Заголовки.Вставить("Content-Type", "application/xml; charset=utf-8");
    
    // Передаем путь к файлу. Платформа сама посчитает Content-Length в байтах!
    Запрос.УстановитьИмяФайлаТела(ПутьКФайлуXML);
    
    // 4. Отправка запроса и получение ответа
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        
        // Проверяем успешность выполнения запроса на уровне протокола HTTP
        Если Ответ.КодСостояния = 200 Тогда
            
            // Получаем текст ответа напрямую из памяти без промежуточных файлов
            СтрокаОтветаСервера = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
            
            // Здесь выполняем обработку полученного ответа (например, чтение XML-ответа)
            ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Запрос успешно выполнен! Ответ сервера: " + СтрокаОтветаСервера);
            
        Иначе
            // Сервер вернул ошибку обработки (например, 400, 404, 500)
            СтрокаОшибкиСервера = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
            ВызватьИсключение "Сервер вернул код состояния: " + Ответ.КодСостояния + ". Текст ошибки: " + СтрокаОшибкиСервера;
        КонецЕсли;
        
    Исключение
        // Фиксируем системную или сетевую ошибку в Журнале регистрации
        ЗаписатьЖурналРегистрации(
            "Интеграция.ОтправкаXML",
            УровеньЖурналаРегистрации.Ошибка,
            ,
            ,
            "Произошла ошибка при отправке XML: " + ОписаниеОшибки()
        );
        ВызватьИсключение "Не удалось отправить данные. Подробности смотрите в Журнале регистрации.";
    КонецПопытки;
    
    // 5. Обязательная очистка временных ресурсов на диске
    Попытка
        УдалитьФайлы(ПутьКФайлуXML);
    Исключение
        // Ошибка удаления временного файла не должна прерывать основную логику
        ЗаписатьЖурналРегистрации(
            "Интеграция.ОчисткаФайлов",
            УровеньЖурналаРегистрации.Предупреждение,
            ,
            ,
            "Не удалось удалить временный файл: " + ПутьКФайлуXML + ". Ошибка: " + ОписаниеОшибки()
        );
    КонецПопытки;

КонецПроцедуры

Альтернативный вариант: когда XML действительно маленький (до 1-2 МБ)

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

Для реализации этого сценария мы воспользуемся объектом ЗаписьXML с методом УстановитьСтроку(). Рассмотрим пример:


&НаСервере
Функция СформироватьXMLВСтроку()
    
    ЗаписьXML = Новый ЗаписьXML;
    
    // Открываем запись в строку без использования BOM маркера
    ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", , Ложь);
    ЗаписьXML.УстановитьСтроку(ПараметрыЗаписи);
    
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    ЗаписьXML.ЗаписатьНачалоЭлемента("Root");
    ЗаписьXML.ЗаписатьНачалоЭлемента("SmallData");
    ЗаписьXML.ЗаписатьТекст("Передача небольшого объема данных");
    ЗаписьXML.ЗаписатьКонецЭлемента();
    ЗаписьXML.ЗаписатьКонецЭлемента();
    
    Возврат ЗаписьXML.Закрыть(); // Возвращает готовую строку XML
    
КонецФункции

&НаСервере
Процедура ОтправитьМалыйXMLНаСервер()
    
    XMLСтрокаДанных = СформироватьXMLВСтроку();
    
    Соединение = Новый HTTPСоединение("192.168.20.12", 7000, , , , 30);
    Запрос = Новый HTTPЗапрос("/cwms/ws/NOM.DEV");
    
    Запрос.Заголовки.Вставить("Content-Type", "application/xml; charset=utf-8");
    
    // Передаем строку напрямую. Платформа сама переведет ее в UTF-8 и рассчитает Content-Length в байтах
    // Указываем ИспользованиеByteOrderMark.НеИспользовать, чтобы избежать ошибок парсинга на сервере
    Запрос.УстановитьТелоИзСтроки(XMLСтрокаДанных, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        Если Ответ.КодСостояния = 200 Тогда
            СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
            // Обработка ответа...
        КонецЕсли;
    Исключение
        // Обработка исключений...
    КонецПопытки;
    
КонецПроцедуры

Резюме и рекомендации

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

  1. Откажитесь от ручного расчета длины: Забудьте про вычисление размера заголовка Content-Length вручную через СтрДлина(). Доверьте это платформе 1С.
  2. Контролируйте размер данных: Для файлов размером более 5-10 МБ всегда используйте метод HTTPЗапрос.УстановитьИмяФайлаТела() с записью данных во временный файл. Это убережет сервер 1С от падения из-за нехватки оперативной памяти.
  3. Избегайте BOM: При отправке данных на сторонние веб-сервисы всегда отключайте маркер порядка байтов BOM (Byte Order Mark), указывая Ложь в параметрах записи XML или ИспользованиеByteOrderMark.НеИспользовать при работе со строками.
  4. Проверяйте параметры сети: Корректно разделяйте использование защищенных соединений HTTPS и работу на кастомных портах HTTP.

Используя предложенные шаблоны кода, вы сможете построить надежную и быструю интеграцию с любой WMS или учетной системой, экономя время и ресурсы вашего сервера.

← На главную