При разработке механизмов интеграции в среде 1С:Предприятие 7.7 программисты часто сталкиваются с нестабильной работой системы при попытке передать значительные объемы данных (от 300 КБ и выше) через стандартный COM-объект WinHttp.WinHttpRequest.5.1. Проблема проявляется максимально жестко: приложение просто «рубится» и закрывается без генерации каких-либо диагностических сообщений. В этой статье мы подробно разберем, почему это происходит, и рассмотрим несколько эффективных способов решения проблемы.
Прежде чем переходить к коду, проанализируем ситуацию с технической точки зрения. Платформа 1С 7.7 — это 32-битное приложение с архитектурой конца 90-х годов. Основная причина вылета при работе с WinHttp заключается в маршалинге строк. Когда мы передаем переменную типа «строка» в метод Send() COM-объекта, движок 1С пытается преобразовать внутреннее представление строки в формат BSTR (Basic String), используемый в COM. Если строка очень длинная, внутренний менеджер памяти 1С может не найти подходящего непрерывного блока памяти или некорректно обработать выделение буфера, что приводит к ошибке Access Violation.
Дополнительным негативным фактором выступает фрагментация памяти. Если вы собираете JSON-строку в цикле обычным сложением (Стр = Стр + "фрагмент"), 1С постоянно создает в памяти новые копии строки, забивая кучу мелкими фрагментами. К моменту вызова Send() свободного непрерывного пространства просто не остается.
Как показала практика обсуждения на форуме, наиболее стабильным решением для старых систем является вынос транспортного уровня за пределы процесса 1С. Утилита curl прекрасно справляется с передачей файлов любого размера.
Разберем алгоритм по шагам:
Пример реализации на языке 1С 7.7:
// 1. Формируем JSON и сохраняем в файл
Текст = СоздатьОбъект("Текст");
Текст.ДобавитьСтроку(СтрокаJSON);
ПутьКФайлуЗапроса = "C:\temp\request.json";
Текст.Записать(ПутьКФайлуЗапроса);
// 2. Формируем команду для curl
// Используем флаг -d @путь_к_файлу для отправки содержимого файла
Команда = "curl.exe -X POST https://api.server.ru/data -H ""Content-Type: application/json"" -d @""" + ПутьКФайлуЗапроса + """";
// 3. Запускаем выполнение
КомандаСистемы(Команда);
Важное замечание: Если вы работаете на Windows XP, современные версии curl могут не запуститься. В этом случае необходимо искать старые релизы на официальном сайте в разделе «Old releases». Также помните, что для работы по HTTPS современным серверам требуется поддержка протокола TLS 1.2, которая в XP по умолчанию ограничена.
Если вы не хотите использовать внешние исполняемые файлы, существует «элегантный» способ обмануть менеджер памяти 1С. Вместо передачи строки напрямую в WinHttp, мы передадим объект потока. В этом случае 1С передает COM-объекту не копию данных, а ссылку на интерфейс, и WinHttp сам считывает данные из памяти потока.
Рассмотрим пример использования ADODB.Stream для отправки данных в кодировке UTF-8:
// Создаем объект WinHttp
Http = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
Http.Open("POST", "https://api.server.com/upload", 0);
Http.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
// Используем ADODB.Stream для подготовки данных
Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 2; // adTypeText
Поток.Charset = "utf-8";
Поток.Open();
Поток.WriteText(ДлиннаяСтрокаJSON);
// Переходим к двоичным данным, чтобы WinHttp корректно их прочитал
Поток.Position = 0;
Поток.Type = 1; // adTypeBinary
// Отправляем тело запроса как объект
Http.Send(Поток.Read());
Этот метод позволяет отправлять объекты размером в десятки мегабайт без риска обрушить процесс 1С, так как основная работа с памятью перекладывается на системные библиотеки Windows.
Проанализируем альтернативный объект — MSXML2.ServerXMLHTTP. В некоторых конфигурациях систем он ведет себя более стабильно, чем WinHttpRequest, особенно при работе в многопоточной среде (например, если 1С запущена на терминальном сервере). Он имеет схожий синтаксис, но лучше оптимизирован для обработки больших XML и JSON пакетов.
Http = СоздатьОбъект("MSXML2.ServerXMLHTTP");
Http.Open("POST", URL, 0);
Http.SetRequestHeader("Content-Type", "application/json");
Http.Send(ДлиннаяСтрокаJSON);
Если ваша инфраструктура все еще включает точки на Windows XP, вы столкнетесь с тем, что даже рабочий код будет выдавать ошибку соединения при обращении к современным HTTPS-ресурсам. Это связано с тем, что системный компонент WinHttp в XP не знает о существовании протокола TLS 1.2.
Для решения этой проблемы необходимо:
DefaultSecureProtocols в ветку HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp. Это позволит активировать TLS 1.1 и 1.2 на уровне системы.Чтобы минимизировать вероятность фрагментации памяти еще на этапе формирования запроса, придерживайтесь следующих правил:
S = S + ТекущаяСтрока, используйте объект Текст. Метод ДобавитьСтроку() работает значительно быстрее и экономнее с точки зрения выделения памяти.WinHttp это делается методом SetTimeouts.Подведем итог: если ваша 1С 7.7 вылетает при отправке JSON — это сигнал о переполнении памяти при маршалинге. Используйте либо curl для полной изоляции процесса отправки, либо ADODB.Stream для оптимизированной передачи данных через интерфейсы COM. Оба этих подхода проверены временем и позволяют стабильно работать с объемами данных, значительно превышающими стандартные ограничения 1С.