При интеграции платформы 1С:Предприятие 7.7 с современными веб-сервисами разработчики нередко сталкиваются с ситуацией, когда отправка POST-запроса через COM-объекты завершается аварийным падением программы (Crash / Access Violation) либо наглухо подвешивает процесс. Чаще всего это происходит в тот момент, когда сервер возвращает объемный XML-документ (от нескольких сотен килобайт и более), а платформа пытается прочитать его в строковую переменную или разобрать через объектную модель Msxml2.DOMDocument.
Разберем детально, почему это происходит в среде 1С 7.7, какие архитектурные ограничения операционной системы и платформы вызывают сбой, а также рассмотрим надежные практические способы решения этой задачи.
Выясним причину аварийного завершения работы программы. В типовом коде проблема обычно кроется в комбинации нескольких факторов:
WinHTTP.ResponseText, Узел.text или Узел.xml у крупных пакетов данных заставляет платформу считывать весь объем в память целиком, что провоцирует падение при превышении лимитов.//*[local-name() = 'payload'] отключают встроенную оптимизацию и индексацию узлов парсера MSXML. Движок вынужден выполнять полный линейный перебор абсолютно каждого узла документа со сравнением строк, что на глубоких или объемных структурах приводит к экспоненциальному росту нагрузки на процессор и память.Узел.SelectNodes("//*[...]") ищет совпадения не внутри текущего элемента, а всегда от корня всего документа. В цикле это приводит к многократному повторному обходу гигантского дерева. Для поиска среди дочерних элементов контекстного узла путь обязательно должен начинаться с точки: .//*[...].CreateObject("Msxml2.DOMDocument") нередко подгружает устаревшие системные библиотеки (например, MSXML 3.0), которые обладают жесткими ограничениями по глубине рекурсии и объему DOM-дерева в памяти.Рассмотрим наиболее элегантный и производительный способ, который позволяет полностью исключить чтение больших строк силами самой 1С 7.7. Вместо связки WinHttp.WinHttpRequest.5.1 и вызова ДОМ.loadXML(СтрокаОтвета) переведем отправку запроса на компонент Msxml2.ServerXMLHTTP. Этот объект умеет отдавать результат запроса напрямую в виде готового DOM-документа через свойство responseXML.
Посмотрим на практическую реализацию:
XMLHTTP = СоздатьОбъект("Msxml2.ServerXMLHTTP.6.0");
XMLHTTP.open("POST", "https://www.audatex.ru/b2b/services/TaskService_v1", 0);
XMLHTTP.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
XMLHTTP.setRequestHeader("SOAPAction", "url_действия");
// Передаем сформированное тело запроса
XMLHTTP.send(глПреобразоватьСтрокуВUTF8(wsdlRequest));
Если XMLHTTP.Status = 200 Тогда
// Получаем DOM напрямую из HTTP-клиента без промежуточного ResponseText
ДОМ = XMLHTTP.responseXML;
ДОМ.setProperty("SelectionLanguage", "XPath");
// Задаем пространство имен для быстрого поиска
ДОМ.setProperty("SelectionNamespaces", "xmlns:ser='http://serviceinterface_v1.b2b.audatex.com'");
// Выбираем узлы без использования ресурсоемкого local-name()
СписокУзлов = ДОМ.selectNodes("//ser:payload");
Сообщить("Найдено узлов: " + Строка(СписокУзлов.length));
Иначе
Сообщить("Ошибка запроса. Статус сервера: " + Строка(XMLHTTP.Status));
КонецЕсли;
В этом сценарии большой текст XML вообще не попадает в строковые переменные 1С, а парсится внутренней библиотекой C++ на уровне системных компонентов Windows.
Проанализируем ситуацию, когда необходимо разобрать структуру с префиксами пространств имен. Использование функций вида local-name() создает критическую нагрузку. Перепишем логику с явным указанием пространств имен через свойство SelectionNamespaces и корректным указанием относительных путей.
Разберем правильный алгоритм обхода вложенных узлов:
// Отключаем валидацию и внешние резолверы для ускорения
ДОМ.async = 0;
ДОМ.validateOnParse = 0;
ДОМ.resolveExternals = 0;
ДОМ.setProperty("SelectionLanguage", "XPath");
// Объявляем пространства имен документа
ДОМ.setProperty("SelectionNamespaces", "xmlns:ser='http://serviceinterface_v1.b2b.audatex.com' xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'");
// Получаем корневой список задач
СписокЗадач = ДОМ.selectNodes("//ser:Task");
Для х = 0 По СписокЗадач.length - 1 Цикл
УзелЗадачи = СписокЗадач.item(х);
// ВНИМАНИЕ: относительный поиск от текущего узла должен начинаться с точки!
УзелИдентификации = УзелЗадачи.selectSingleNode(".//ser:VehicleIdentification");
Если ПустоеЗначение(УзелИдентификации) = 0 Тогда
УзелVIN = УзелИдентификации.selectSingleNode("ser:VIN");
Если ПустоеЗначение(УзелVIN) = 0 Тогда
Сообщить("VIN: " + УзелVIN.text);
КонецЕсли;
УзелМарки = УзелИдентификации.selectSingleNode("ser:ManufacturerName");
Если ПустоеЗначение(УзелМарки) = 0 Тогда
Сообщить("Марка: " + УзелМарки.text);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если специфика интеграции требует использования WinHttp.WinHttpRequest.5.1, обойдем ограничение на чтение больших строк через сохранение сырого бинарного ответа в файл на жестком диске. Метод ДОМ.load(ИмяФайла) оптимизирован значительно лучше, чем строковый loadXML().
Посмотрим, как организовать сохранение тела ответа без потери кодировки через ADODB.Stream и MSScriptControl:
Если WinHTTP.Status = 200 Тогда
ВременныйФайл = КаталогВременныхФайлов() + "response_" + _GetPerformanceCounter() + ".xml";
// Создаем поток для бинарной записи ответа сервера
Стрим = СоздатьОбъект("ADODB.Stream");
Стрим.Type = 1; // adTypeBinary
Стрим.Open();
// Передаем байты из WinHTTP в поток с помощью ScriptControl
Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "VBScript";
Скрипт.AddObject("WinHttp", WinHTTP);
Скрипт.AddObject("Stream", Стрим);
Скрипт.Eval("Stream.Write(WinHttp.responseBody)");
// Сохраняем поток на диск
Стрим.SaveToFile(ВременныйФайл, 2); // 2 = adSaveCreateOverWrite
Стрим.Close();
// Загружаем сформированный файл напрямую в DOM
ДОМ = СоздатьОбъект("Msxml2.DOMDocument.6.0");
ДОМ.async = 0;
ДОМ.load(ВременныйФайл);
// Удаляем временный файл после парсинга
ФС.УдалитьФайл(ВременныйФайл);
Иначе
Сообщить("Ошибка HTTP: " + Строка(WinHTTP.Status));
КонецЕсли;
Применение этих методов позволяет полностью стабилизировать работу платформы 1С 7.7 при обработке объемных XML-пакетов данных и исключить аварийные падения системы.