Как запустить внешнюю ссылку или приложение на сервере 1С из регламентного задания?

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

Когда вы работаете с платформой 1С:Предприятие, особенно при разработке функционала, требующего взаимодействия с внешними системами или запуска приложений, вы можете столкнуться с необходимостью выполнить эти действия на сервере. Однако, если вы попытаетесь использовать стандартную процедуру ЗапуститьПриложение() в серверном коде, особенно в регламентных заданиях, то столкнетесь с ошибками или отсутствием реакции. В этой статье мы подробно разберем, почему так происходит, и предложим эффективное решение с использованием HTTP-запросов для сигнализирования внешним веб-сервисам, а также рассмотрим другие альтернативы для выполнения команд на сервере.

Понимание ограничений ЗапуститьПриложение() на сервере 1С

Давайте выясним, почему процедура ЗапуститьПриложение(), которая отлично работает в клиентском коде, становится бесполезной на сервере.

  1. Предназначение для клиентской стороны: Процедура ЗапуститьПриложение() изначально разработана для запуска внешних программ или открытия файлов в контексте клиентского приложения 1С. Это означает, что она ожидает наличия интерактивного пользовательского сеанса и доступа к рабочему столу, чтобы, например, открыть браузер, текстовый редактор или выполнить командный файл.
  2. Отсутствие интерактивного сеанса на сервере: Сервер 1С, особенно при выполнении регламентных заданий, работает в фоновом режиме без какого-либо графического интерфейса или пользовательского сеанса. Он не имеет "рабочего стола", на котором могли бы быть запущены приложения. Поэтому, когда вы вызываете ЗапуститьПриложение() из серверного кода, система не может найти среду для выполнения запрошенного действия, что приводит к ошибке или игнорированию команды.
  3. Контекст выполнения регламентных заданий: Регламентные задания всегда выполняются на сервере 1С, независимо от того, запущено ли клиентское приложение на том же компьютере. Таким образом, даже если сервер и клиент находятся на одной машине, код регламентного задания будет выполняться в серверном контексте, где ЗапуститьПриложение() не работает.

Очевидно, что ЗапуститьПриложение() не подходит для нашей задачи сигнализации сайту из регламентного задания. Нам нужно найти способ взаимодействия с внешними системами, который предназначен для серверного выполнения.

HTTP-запросы: оптимальное решение для взаимодействия с внешними веб-системами

Как было справедливо отмечено в обсуждении, HTTP-запросы являются наиболее предпочтительным и надежным способом для взаимодействия с внешними веб-сервисами и сайтами из серверного кода 1С, включая регламентные задания. Этот метод стандартизирован, безопасен (особенно с использованием HTTPS) и полностью поддерживается платформой 1С для выполнения в фоновом режиме.

Основные объекты 1С для работы с HTTP-запросами

Для реализации HTTP-запросов в 1С мы будем использовать три ключевых объекта:

  1. HTTPСоединение: Этот объект отвечает за установление связи с удаленным сервером. В его конструкторе мы указываем адрес сервера (хост), порт, данные для аутентификации (если требуются), параметры прокси-сервера и, что очень важно для HTTPS, объект защищенного соединения.
  2. HTTPЗапрос: С помощью этого объекта мы формируем сам запрос. Здесь мы определяем путь к ресурсу на сервере, метод запроса (например, GET, POST), добавляем необходимые заголовки (например, для авторизации или указания типа содержимого) и тело запроса (для POST-запросов).
  3. HTTPОтвет: Это результат выполнения нашего запроса. Из объекта HTTPОтвет мы можем получить код состояния HTTP (например, 200 для успеха, 404 для не найдено, 500 для ошибки сервера), заголовки ответа и тело ответа, которое может содержать данные в текстовом или двоичном формате.

Шаг 1: Установка защищенного HTTP-соединения (HTTPS)

Большинство современных веб-сайтов используют защищенный протокол HTTPS для обеспечения конфиденциальности и целостности данных. Для работы с HTTPS в 1С нам потребуется объект ЗащищенноеСоединениеOpenSSL. Рассмотрим, как правильно создать объект HTTPСоединение для HTTPS.

Предположим, наш сайт — МойСайт.com, и нам нужно отправить запрос по HTTPS. Код будет выглядеть следующим образом:


HTTP = Новый HTTPСоединение(
    "МойСайт.com", // сервер (хост)
    443, // порт, по умолчанию для HTTP используется 80, для HTTPS 443
    , // пользователь для доступа к серверу (если он есть, для базовой аутентификации)
    , // пароль для доступа к серверу (если он есть)
    , // здесь указывается прокси, если он есть (объект ИнтернетПрокси)
    0, // таймаут в секундах, 0 или пусто - не устанавливать
    Новый ЗащищенноеСоединениеOpenSSL() // объект защищенного соединения для HTTPS
);

Разберем параметры подробнее:

Важный момент: Если ваш сайт использует HTTP вместо HTTPS, то порт будет 80, и параметр ЗащищенноеСоединениеOpenSSL() не нужен. Однако для безопасности всегда рекомендуется использовать HTTPS.

Шаг 2: Формирование HTTP-запроса

После установления соединения мы должны сформировать сам запрос, указав путь к ресурсу на сервере.

Предположим, нам нужно вызвать URL https://МойСайт.com/index.php?route=feed/import1c для сигнализации о загрузке файла. Объект HTTPЗапрос формируется следующим образом:


ПутьРесурса = "/index.php?route=feed/import1c";
Запрос = Новый HTTPЗапрос(ПутьРесурса);

А если ссылка выглядит как https://МойСайт.com/some/path/to/signal, без `.php` на конце?

Абсолютно никаких проблем! Веб-сервер сам знает, как обрабатывать такие URL (например, с помощью правил перенаправления или маршрутизации). Для объекта HTTPЗапрос важно только указать относительный путь от корня доменного имени. В этом случае, путь будет:


ПутьРесурса = "/some/path/to/signal";
Запрос = Новый HTTPЗапрос(ПутьРесурса);

Если вам нужно передать данные в запросе (например, параметры через POST-запрос или заголовки), вы можете использовать соответствующие методы объекта HTTPЗапрос, такие как УстановитьТелоИзСтроки(), УстановитьТелоИзДвоичныхДанных(), УстановитьЗаголовки().

Шаг 3: Отправка запроса и обработка ответа

Теперь, когда у нас есть настроенное соединение и сформированный запрос, мы можем отправить его и получить ответ.

Ответ = HTTP.Получить(Запрос);

Метод Получить() для HTTPСоединения используется для отправки GET-запроса. Если вам нужно отправить POST-запрос, вы используете метод Отправить(), передавая в него объект HTTPЗапрос, в котором уже настроено тело запроса.

После получения объекта Ответ нам необходимо проанализировать его, чтобы убедиться, что запрос был обработан успешно. Ключевым является свойство КодСостояния.

  1. Код состояния 200-299: Это диапазон кодов, который обычно указывает на успешное выполнение запроса.
  2. Код состояния 400-499: Ошибки на стороне клиента. Например, 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found).
  3. Код состояния 500-599: Ошибки на стороне сервера. Например, 500 (Internal Server Error).

Мы также можем получить тело ответа (если сервер что-то возвращает) с помощью методов ПолучитьТелоКакСтроку() или ПолучитьТелоКакДвоичныеДанные().

Полный пример кода для сигнализации сайту по HTTPS

Объединим все шаги в единый фрагмент кода, который можно использовать в серверной процедуре регламентного задания:


&НаСервере
Процедура СигнализироватьСайтуОЗагрузкеФайла()

    // -----------------------------------------------------------
    // Параметры для подключения к сайту
    // -----------------------------------------------------------
    СерверСайта = "МойСайт.com"; // Доменное имя вашего сайта
    Порт = 443; // Порт для HTTPS. Для HTTP используйте 80
    // Пользователь и пароль для базовой HTTP-аутентификации, если требуется
    // ИмяПользователяСайта = "вашЛогин";
    // ПарольСайта = "вашПароль";

    // Относительный путь к ресурсу на сайте, который нужно вызвать
    // Например, для URL https://МойСайт.com/index.php?route=feed/import1c -> "/index.php?route=feed/import1c"
    // Для URL https://МойСайт.com/some/path/to/signal -> "/some/path/to/signal"
    ПутьРесурса = "/index.php?route=feed/import1c"; // Пример пути

    // Таймаут ожидания ответа от сервера в секундах. 0 - без таймаута.
    // Рекомендуется устанавливать разумное значение.
    Таймаут = 30;

    // -----------------------------------------------------------
    // Выполнение HTTP-запроса
    // -----------------------------------------------------------
    Попытка
        // 1. Создаем объект защищенного соединения для HTTPS
        ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();

        // 2. Устанавливаем HTTP-соединение с сайтом
        // Если требуется базовая аутентификация, раскомментируйте параметры ИмяПользователяСайта и ПарольСайта
        HTTP = Новый HTTPСоединение(
            СерверСайта,
            Порт,
            , // ИмяПользователяСайта,
            , // ПарольСайта,
            , // Прокси-сервер (объект ИнтернетПрокси), если используется
            Таймаут,
            ЗащищенноеСоединение
        );

        // 3. Формируем HTTP-запрос
        Запрос = Новый HTTPЗапрос(ПутьРесурса);
        // Если нужны дополнительные заголовки (например, для POST-запроса или токена авторизации):
        // Заголовки = Новый Соответствие;
        // Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
        // Заголовки.Вставить("Authorization", "Bearer ВашТокен");
        // Запрос.УстановитьЗаголовки(Заголовки);

        // Если это POST-запрос с телом (например, JSON-данные):
        // ТелоЗапроса = "{\"ключ\":\"значение\"}";
        // Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8);

        // 4. Отправляем запрос и получаем ответ
        // Для GET-запроса используем Получить(), для POST-запроса - Отправить(Запрос)
        Ответ = HTTP.Получить(Запрос); // Для нашего случая сигнализации, скорее всего, это GET-запрос

        // 5. Анализируем ответ от сервера
        Если Ответ.КодСостояния = 200 Тогда
            Сообщить("Успешная сигнализация сайту '" + СерверСайта + "'. Ответ сервера: " + Ответ.ПолучитьТелоКакСтроку());
            // Здесь можно добавить логику обработки успешного ответа
        Иначе
            Сообщить("Ошибка при сигнализации сайту '" + СерверСайта + "'. Код состояния: " + Ответ.КодСостояния);
            Сообщить("Детали ошибки: " + Ответ.ПолучитьТелоКакСтроку());
            // Здесь можно добавить логику обработки ошибки, например, повтор запроса или логирование
        КонецЕсли;

    Исключение
        Сообщить("Произошла критическая ошибка при выполнении HTTP-запроса: " + ОписаниеОшибки());
        // Дополнительное логирование ошибок в журнал регистрации 1С
        ЗаписьЖурналаРегистрации(
            "HTTP-запрос",
            УровеньЖурналаРегистрации.Ошибка,
            , // ОбъектМетаданных
            , // Данные
            "Ошибка сигнализации сайту: " + ОписаниеОшибки()
        );
    КонецПопытки;

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

Альтернативы ЗапуститьПриложение() для выполнения серверных команд (не для веб-сигнализации)

Хотя HTTP-запросы являются лучшим решением для взаимодействия с веб-сайтами, могут возникнуть ситуации, когда вам нужно выполнить какую-то команду непосредственно на сервере 1С (например, запустить локальную утилиту или скрипт). Для таких случаев есть другие подходы:

  1. ФайловаяСистема.ЗапуститьПрограмму() (из БСП): Если ваша конфигурация использует Библиотеку стандартных подсистем (БСП), то в ней есть метод ЗапуститьПрограмму(). Этот метод позволяет более безопасно и контролируемо запускать внешние исполняемые файлы на сервере, а также получать код возврата и вывод программы (stdout, stderr). Это значительно предпочтительнее прямого использования WScript.Shell, так как он обычно имеет более продуманную обертку и обработку безопасности.
  2. Использование COM-объектов WScript.Shell: В некоторых случаях можно использовать COM-объект WScript.Shell для выполнения команд на сервере. Однако этот метод имеет ряд ограничений и рисков:
    • Требует наличия и корректной регистрации COM-объекта на сервере.
    • Сопряжено с рисками безопасности, так как позволяет выполнять произвольные команды операционной системы от имени пользователя, под которым запущен сервер 1С.
    • Синтаксис:
      
      Shell = Новый COMОбъект("WScript.Shell");
      Результат = Shell.Run("cmd /c echo Hello World > C:\temp\log.txt", 0, Истина);
      // 0 - стиль окна (скрытое), Истина - ждать завершения
      
      Мы настоятельно не рекомендуем использовать WScript.Shell без глубокого понимания всех рисков и строжайшего контроля над исполняемыми командами.

Для нашей изначальной задачи сигнализации сайту, HTTP-запросы остаются лучшим и самым безопасным решением.

Важные нюансы и возможные проблемы

При работе с HTTP-запросами и регламентными заданиями необходимо учитывать следующие моменты:

  1. Таймаут: Всегда устанавливайте адекватный таймаут для HTTPСоединения. Если внешний ресурс долго не отвечает, отсутствие таймаута может привести к зависанию регламентного задания и нехватке свободных рабочих процессов сервера 1С.
  2. Прокси-сервер: Если ваш сервер 1С находится в корпоративной сети, скорее всего, ему нужен доступ в интернет через прокси-сервер. В таком случае, необходимо создать и настроить объект ИнтернетПрокси и передать его в конструктор HTTPСоединения.
  3. Кодировка: При отправке тела запроса (особенно для POST-запросов) или получении ответа, обращайте внимание на кодировку текста. Чаще всего используется КодировкаТекста.UTF8. Неправильная кодировка может привести к "кракозябрам" или некорректной обработке данных.
  4. Журнал регистрации: Всегда логируйте важные этапы выполнения HTTP-запросов и особенно ошибки в журнал регистрации 1С. Это бесценно для диагностики проблем, особенно в регламентных заданиях, которые выполняются в фоновом режиме.
  5. Сертификаты и SSL-соединение: Проблемы с HTTPS могут возникать из-за устаревших или отсутствующих корневых сертификатов на сервере 1С, настроек брандмауэра или сетевых ограничений. Убедитесь, что сервер 1С имеет доступ к внешнему IP-адресу и порту (обычно 443) целевого сайта. В некоторых сложных случаях может потребоваться импорт сертификатов удостоверяющих центров на сервер 1С.
  6. Версия платформы 1С: Функциональность и стабильность работы объектов для HTTP-запросов улучшались с развитием платформы. Для полноценной и надежной работы с HTTP-соединениями рекомендуется использовать платформу 8.3.17 и выше.
  7. Доступ в интернет для сервера 1С: Убедитесь, что сам сервер 1С имеет разрешение на исходящие подключения в интернет через брандмауэр и сетевые правила.

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

← На главную