Разработка и поддержка систем на базе платформы 1С:Предприятие 7.7 в современных реалиях часто ставит перед программистами сложные задачи, связанные со взаимодействием с внешними веб-сервисами. Одной из самых частых и востребованных задач является загрузка и сохранение на диск файлов по защищенному протоколу HTTPS. На первый взгляд, задача тривиальна — использовать стандартные системные OLE-объекты Windows, такие как Microsoft.XMLHTTP или WinHttp.WinHttpRequest.5.1 в связке с объектом ADODB.Stream. Однако при попытке выполнить запись полученного бинарного потока напрямую разработчик сталкивается с непреодолимым ограничением платформы.
В этой статье мы детально проанализируем, почему возникает популярная ошибка «Тип переменной не поддерживается», разберем классическое решение этой проблемы с использованием скриптового контейнера, а также рассмотрим современные альтернативные варианты, которые гарантируют стабильную работу на современных операционных системах Windows 10 и Windows 11 с поддержкой протоколов шифрования TLS 1.2 и TLS 1.3.
Рассмотрим классический пример кода, который часто пытаются использовать для загрузки файлов:
XMLHTTP = CreateObject("Microsoft.XMLHTTP");
XMLHTTP.Open("GET", url, 0);
Попытка
XMLHTTP.Send();
Исключение
Сообщить("Ошибка отправки запроса: " + ОписаниеОшибки(), "!");
Возврат;
КонецПопытки;
ADOStream = CreateObject("ADODB.Stream");
ADOStream.Type = 1; // Указываем бинарный тип данных
ADOStream.Open();
ADOStream.Write(XMLHTTP.responseBody);
ADOStream.SaveToFile(ПутьКФайлу + "file.dat", 2);
При выполнении этого кода на строке ADOStream.Write(XMLHTTP.responseBody) система 1С 7.7 аварийно прерывает выполнение процесса с ошибкой: «Тип переменной не поддерживается». Давайте разберем природу этого поведения.
Проблема кроется в архитектурных ограничениях встроенного языка 1С 7.7. Метод responseBody OLE-объекта HTTP-запроса возвращает массив двоичных данных в формате SafeArray (тип данных VT_ARRAY | VT_UI1). Платформа 1С 7.7 физически не умеет обрабатывать этот тип данных на уровне своего ядра. Она не способна ни считать его напрямую, ни передать в качестве аргумента методу другого OLE-объекта (в нашем случае — методу Write объекта ADODB.Stream).
Попытки заменить свойство responseBody на текстовое свойство responseText решают проблему несовместимости типов, но приводят к повреждению скачиваемых файлов. Текстовое свойство пытается интерпретировать бинарные данные как символы в определенной кодировке, что безвозвратно искажает структуру исполняемых файлов, архивов или картинок.
Для того чтобы обойти ограничение 1С 7.7 на работу с бинарными массивами SafeArray, мы можем использовать встроенный в Windows скриптовый движок. Объект MSScriptControl.ScriptControl позволяет выполнять код на языках VBScript или JScript прямо внутри адресного пространства процесса 1С. Поскольку эти скриптовые языки полноценно поддерживают работу с SafeArray на уровне ядра операционной системы, они могут без проблем передать бинарный поток из одного COM-объекта в другой.
Разберем по шагам реализацию этого метода. Мы создадим вспомогательную процедуру, которая будет принимать объект HTTP-запроса и целевой путь к файлу на диске. Внутри этой процедуры мы настроим скриптовый контейнер, передадим в него наши OLE-объекты и выполним запись файла средствами VBScript.
//*******************************************
Процедура СохранитьВФайл(http, ИмяФайла)
// Создаем объект скрипт-контроля
Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "vbscript";
// Создаем объект потока ADODB
stream = СоздатьОбъект("ADODB.Stream");
stream.Mode = 3; // Разрешаем чтение и запись
stream.Type = 1; // Указываем бинарный формат данных
stream.Open();
// Передаем объекты в контекст выполнения скрипта
Скрипт.AddObject("stream", stream);
Скрипт.AddObject("http", http);
// Выполняем запись бинарного ответа в поток средствами VBScript
Скрипт.Eval("stream.Write(http.responseBody)");
// Сохраняем поток в файл на диске
stream.SaveToFile(ИмяФайла, 2); // Параметр 2 означает перезапись файла при наличии
stream.Close();
КонецПроцедуры
//*******************************************
Процедура СкачатьФайл()
// Рекомендуется использовать ServerXMLHTTP вместо устаревшего XMLHTTP
http = СоздатьОбъект("Msxml2.ServerXMLHTTP");
// Инициализируем GET-запрос к файлу
http.open("GET", "https://example.com/file.zip", 0);
http.send();
// Проверяем статус ответа сервера
Если http.status = 200 Тогда
СохранитьВФайл(http, "C:\temp\downloaded_file.zip");
Сообщить("Файл успешно сохранен!");
Иначе
Сообщить("Ошибка сервера: " + http.status + " " + http.statusText, "!");
КонецЕсли;
КонецПроцедуры
Этот способ отлично решает проблему несовместимости типов данных и позволяет скачивать любые бинарные файлы без повреждения их внутренней структуры.
При переходе на работу по протоколу HTTPS разработчики часто сталкиваются с тем, что код успешно выполняется на тестовых HTTP-ресурсах, но при обращении к реальным защищенным сайтам падает на этапе вызова метода Send() с ошибками сетевого подключения или SSL-сертификатов (например, код ошибки 0x80072EFE или 0x2f8f). Почему это происходит?
Современные веб-серверы из соображений безопасности полностью отказываются от устаревших и уязвимых протоколов шифрования SSL 2.0, SSL 3.0, TLS 1.0 и TLS 1.1. Стандартом де-факто сейчас являются протоколы TLS 1.2 и TLS 1.3.
Системные компоненты WinHttp.WinHttpRequest.5.1 и Msxml2.ServerXMLHTTP на устаревших операционных системах (или без соответствующих системных обновлений) по умолчанию пытаются использовать для соединения TLS 1.0. В результате сервер просто сбрасывает "небезопасное" соединение.
Для решения этой проблемы мы рекомендуем два подхода:
WinHttp.WinHttpRequest.5.1 мы можем принудительно установить использование TLS 1.2. Для этого используется специальная опция безопасности под номером 9. Значение 2048 активирует использование протокола TLS 1.2. Обратите внимание, что на старых ОС (например, Windows 7) для работы этого флага должно быть установлено обновление системы безопасности KB3140245.DefaultSecureProtocols со значением 0x00000800 (или 0x00000A00 для одновременной поддержки TLS 1.1 и TLS 1.2).Параметры должны быть прописаны в следующих ветках реестра:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttpHKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp (данный раздел является ключевым для работы 32-битного процесса 1С 7.7 в 64-битной среде Windows).Несмотря на то, что использование скриптового контейнера долгое время оставалось основным решением проблемы с бинарными данными в 1С 7.7, в современных операционных системах Windows 10, Windows 11 и последних версиях Windows Server данный компонент использовать не рекомендуется. Проанализируем причины:
MSScriptControl является строго 32-битным компонентом. На современных ОС она часто не зарегистрирована в системе по умолчанию, что требует от системного администратора ручной регистрации библиотеки через утилиту regsvr32.Чтобы избежать этих проблем, рассмотрим современные альтернативные варианты загрузки файлов, которые не используют внутренние двоичные преобразования в 1С и работают максимально стабильно.
Начиная с Windows 10 (сборка 1803) и в операционных системах Windows 11, в состав дистрибутива операционной системы по умолчанию входит консольная утилита curl.exe. Эта утилита создана специально для выполнения сетевых запросов и скачивания файлов, обладает великолепной производительностью и полной поддержкой всех современных стандартов шифрования (включая TLS 1.3) «из коробки».
Использование внешней консольной утилиты полностью избавляет нас от необходимости писать сложные обертки на встроенном языке 1С, работать с ADODB.Stream и возиться с несовместимостью типов.
Рассмотрим пример реализации загрузки файла через встроенный curl:
Процедура СкачатьЧерезCurl(АдресСсылки, ПутьКФайлу)
// Формируем командную строку для запуска curl
// Параметр -k отключает строгую проверку SSL-сертификатов (если необходимо)
// Параметр -L заставляет утилиту следовать по перенаправлениям (редиректам)
// Параметр -o указывает путь для сохранения файла на диске
КомандаЗапуска = "curl.exe -k -L -o """ + ПутьКФайлу + """ """ + АдресСсылки + """";
// Запускаем команду операционной системы
КомандаСистемы(КомандаЗапуска);
// Проверяем наличие скачанного файла на диске
ФС = СоздатьОбъект("ФС");
Если ФС.СуществуетФайл(ПутьКФайлу) = 1 Тогда
Сообщить("Файл успешно загружен через Curl!");
Иначе
Сообщить("Не удалось скачать файл через Curl. Проверьте параметры сети.", "!");
КонецЕсли;
КонецПроцедуры
Если ваша база данных запускается на более старых операционных системах (например, Windows 7 или Windows Server 2008 R2), где встроенного curl нет, вы можете скачать скомпилированную 32-битную версию утилиты с официального сайта разработчиков, положить исполняемый файл curl.exe прямо в каталог базы данных (например, в подкаталог ExtForms) и вызывать его, указывая полный путь к файлу.
Еще одним мощным системным инструментом, доступным в любой современной среде Windows, является оболочка PowerShell. С ее помощью мы можем гибко управлять сетевыми протоколами безопасности и скачивать файлы любой сложности в одну строчку кода.
Этот метод особенно ценен тем, что мы можем прямо в командной строке принудительно инициализировать использование протокола TLS 1.2 без изменения глобальных настроек реестра всей операционной системы.
Посмотрим на пример реализации загрузки файла через PowerShell в коде 1С 7.7:
Процедура СкачатьЧерезPowerShell(АдресСсылки, ПутьКФайлу)
// Формируем многострочную команду для PowerShell в одну строку
// 1. Принудительно устанавливаем протокол безопасности TLS 1.2 в текущей сессии .NET
// 2. Создаем объект WebClient и вызываем метод DownloadFile для сохранения файла
КомандаPS = "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; " +
"(New-Object System.Net.WebClient).DownloadFile('" + АдресСсылки + "', '" + ПутьКФайлу + "')";
// Формируем итоговую строку запуска процесса powershell
// Параметр -Command передает скрипт для выполнения
// Параметр -WindowStyle Hidden скрывает черное окно консоли от пользователя
КомандаЗапуска = "powershell -WindowStyle Hidden -Command """ + КомандаPS + """";
// Запускаем внешнее приложение
ЗапуститьПриложение(КомандаЗапуска);
// Проверяем результат
ФС = СоздатьОбъект("ФС");
Если ФС.СуществуетФайл(ПутьКФайлу) = 1 Тогда
Сообщить("Файл успешно загружен через PowerShell!");
Иначе
Сообщить("Ошибка загрузки файла через PowerShell.", "!");
КонецЕсли;
КонецПроцедуры
Использование PowerShell обеспечивает превосходную надежность и гибкость, полностью избавляя разработчиков 1С 7.7 от головной боли с бинарными типами данных.
Каждый из рассмотренных методов имеет свои преимущества и ограничения. Давайте структурируем их, чтобы вы могли выбрать наиболее подходящий вариант для вашей задачи:
curl.exe в каталоге базы.Для создания максимально стабильных решений в современных инфраструктурах мы рекомендуем использовать интеграцию с утилитой Curl или сценариями PowerShell, так как это гарантирует долгосрочную работоспособность вашего решения без необходимости постоянного администрирования операционной системы.