Как исправить ошибку выполнения COM-скрипта при отправке HTTP-запроса и перевести отправку на встроенный объект HTTPСоединение в 1С?

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

При интеграции 1С со сторонними веб-сервисами (например, SMS-шлюзами) в устаревшем коде нередко встречается связка COM-объектов Microsoft.XMLHTTP, MSScriptControl.ScriptControl и ADODB.Stream. На некоторых рабочих станциях такой код внезапно начинает аварийно завершаться ошибкой «Аргументы имеют неверный тип, выходят за пределы допустимого диапазона или вступают в конфликт друг с другом» на строке записи потока. Разберем причины этой проблемы и рассмотрим, как правильно переписать интеграцию с использованием встроенного в платформу 1С объекта HTTPСоединение.

Причины сбоев при использовании COM-объектов

Проанализируем, почему код на базе COM-объектов может стабильно работать на одном компьютере и давать сбой на другом:

  1. Пустое тело ответа при сетевой ошибке. Метод ADODB.Stream.Write() ожидает на вход двоичный массив байтов. Если запрос через Microsoft.XMLHTTP завершился сбоем сети, таймаутом, блокировкой брандмауэра или сервер вернул пустой статус, свойство x.responseBody принимает значение VT_EMPTY или VT_NULL. Попытка передать пустое значение в s.Write() вызывает исключение времени выполнения.
  2. Разрядность платформы 1С. Библиотека MSScriptControl.ScriptControl (файл msscript.ocx) существует исключительно в 32-разрядном исполнении. При запуске кода в 64-разрядном клиенте 1С или в фоновом задании на 64-разрядном сервере данный объект не может инициализироваться или приводит к ошибкам маршалинга типов.
  3. Зависимость от сетевого стека WinINet. Объект Microsoft.XMLHTTP использует системные настройки Internet Explorer конкретного пользователя Windows (версии TLS, кэш, сертификаты, системные параметры прокси-сервера). Различия в настройках учетных записей приводят к нестабильному поведению на разных рабочих местах.

Переход на штатный объект HTTPСоединение

Для надежной работы платформы 1С рекомендуется полностью отказаться от внешних COM-библиотек и переписать логику на штатные объекты HTTPСоединение, HTTPЗапрос и HTTPОтвет.

При переходе важно учесть три ключевых нюанса:

  1. Экранирование параметров (URL-encoding). Параметры строки запроса, содержащие кириллицу, пробелы и спецсимволы (например, знак + в номере телефона), должны быть приведены к безопасному виду. Для этого в платформе 1С применяется функция КодироватьСтроку() с параметром СпособКодированияСтроки.КодировкаURL.
  2. Отключение сжатия gzip со стороны сервера. Если веб-сервер по умолчанию возвращает ответ, сжатый алгоритмом gzip, при обычном чтении в 1С отобразятся нечитаемые символы («кракозябры»). Чтобы сервер вернул открытый текст, передадим в заголовках запроса директиву Accept-Encoding: identity.
  3. Выбор метода запроса (GET или POST). Метод HTTPСоединение.Получить() отправляет HTTP GET-запрос, а метод HTTPСоединение.ОтправитьДляОбработки() используется для отправки HTTP POST-запросов с телом.

Пример реализации GET-запроса средствами 1С

Посмотрим на пример выполнения GET-запроса с получением ответа в виде текста напрямую в переменную без использования временных файлов:


// 1. Формируем безопасные параметры запроса
ТекстСообщения = КодироватьСтроку("Здравствуйте! Ваш заказ готов.", СпособКодированияСтроки.КодировкаURL);
НомерТелефона  = КодироватьСтроку("+79994450987", СпособКодированияСтроки.КодировкаURL);

АдресРесурса = "smw/aisms?action=post_sms"
    + "&user=" + СокрЛП(Константы.ЛогинСМС.Получить())
    + "&pass=" + СокрЛП(Константы.ПарольСМС.Получить())
    + "&sender=" + СокрЛП(Константы.ОтправительСМС.Получить())
    + "&target=" + НомерТелефона
    + "&message=" + ТекстСообщения;

// 2. Настраиваем заголовки
Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept-Encoding", "identity"); // Запрещаем серверу сжимать ответ в gzip

// 3. Создаем соединение и отправляем запрос
HTTPСоединение = Новый HTTPСоединение(
    СокрЛП(Константы.АдресСервераСМС.Получить()), // Хост сервера
    , // Порт (по умолчанию)
    СокрЛП(Константы.ЛогинСМС.Получить()),       // Пользователь базовой аутентификации (если требуется)
    СокрЛП(Константы.ПарольСМС.Получить())        // Пароль базовой аутентификации (если требуется)
);

HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);

// 4. Проверяем код состояния и читаем ответ
Если HTTPОтвет.КодСостояния = 200 Тогда
    ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
    // Обработка полученного XML или JSON
Иначе
    ВызватьИсключение "Ошибка HTTP-запроса: " + HTTPОтвет.КодСостояния;
КонецЕсли;

Пример реализации POST-запроса с передачей параметров в теле

Если веб-сервер ожидает стандартный POST-запрос с типом содержимого application/x-www-form-urlencoded, параметры не следует передавать в адресной строке. Разберем по шагам, как поместить их в тело запроса:


// 1. Формируем тело POST-запроса
ТелоЗапроса = "action=post_sms"
    + "&user=" + КодироватьСтроку(СокрЛП(Константы.ЛогинСМС.Получить()), СпособКодированияСтроки.КодировкаURL)
    + "&pass=" + КодироватьСтроку(СокрЛП(Константы.ПарольСМС.Получить()), СпособКодированияСтроки.КодировкаURL)
    + "&sender=" + КодироватьСтроку(СокрЛП(Константы.ОтправительСМС.Получить()), СпособКодированияСтроки.КодировкаURL)
    + "&target=" + КодироватьСтроку("+79994450987", СпособКодированияСтроки.КодировкаURL)
    + "&message=" + КодироватьСтроку("Проверка отправки", СпособКодированияСтроки.КодировкаURL);

// 2. Устанавливаем заголовки
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
Заголовки.Вставить("Accept-Encoding", "identity");

// 3. Подготавливаем запрос
HTTPЗапрос = Новый HTTPЗапрос("smw/aisms", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);

// 4. Выполняем POST-запрос методом ОтправитьДляОбработки
HTTPСоединение = Новый HTTPСоединение(СокрЛП(Константы.АдресСервераСМС.Получить()));
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);

Если HTTPОтвет.КодСостояния = 200 Тогда
    РезультатXML = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Иначе
    ВызватьИсключение "Ошибка отправки POST-запроса: " + HTTPОтвет.КодСостояния;
КонецЕсли;

Использование встроенных механизмов платформы 1С гарантирует корректную работу в любых режимах запуска (как 32-разрядных, так и 64-разрядных), исключает зависимость от внешних COM-библиотек операционной системы и решает проблемы с кодировками и сетевыми сбоями.

← На главную