Как настроить отправку СМС через шлюз GoIP 4 по POST-запросу из 1С?

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

Рассылка СМС-уведомлений — неотъемлемая часть современных корпоративных систем. Зачастую для этих целей используется специализированное оборудование, такое как VoIP-шлюзы GoIP. В этой статье мы подробно разберем, как реализовать отправку СМС-сообщений через четырехканальный шлюз GoIP 4 из среды «1С:Предприятие». Мы проанализируем различные подходы, начиная от простых GET-запросов и заканчивая сложными POST-запросами с обработкой статусов доставки. Особое внимание уделим адаптации кода под старые версии платформы, такие как 1С 8.1, где отсутствуют многие современные объекты для работы с веб-службами.

Почему стоит использовать POST вместо GET?

Выясним причину, почему разработчики часто стремятся перейти с простых GET-запросов на POST. На первый взгляд, GET-запрос выглядит гораздо проще: в 1С его реализация занимает буквально несколько строк кода. Однако у GET-запросов есть существенные недостатки:

  1. Ограничение на длину передаваемых данных. Длина URL строго лимитирована, что делает невозможным отправку длинных СМС-сообщений.
  2. Безопасность. Чувствительные данные (пароли, ключи авторизации) передаются в открытом виде прямо в строке запроса и могут логироваться серверами и прокси-коммутаторами.
  3. Ограниченность функционала. Метод POST позволяет передавать сложные структурированные данные и является стандартом для взаимодействия с API при отправке сообщений и последующем получении статусов их доставки.

Разбор формата запроса к GoIP 4

Рассмотрим подробнее, как именно шлюз GoIP ожидает получить данные. Часто разработчики допускают ошибку, пытаясь передать тело запроса в формате JSON. Проанализировав поведение веб-интерфейса шлюза GoIP 4 (например, через консоль разработчика в браузере), мы можем увидеть, что устройство работает со стандартной формой кодирования данных application/x-www-form-urlencoded.

Это означает, что тело нашего POST-запроса должно представлять собой строку параметров, соединенных символом амперсанда &, где каждый параметр закодирован в URL-формат.

Типичная строка запроса выглядит следующим образом:

line=1&smskey=5c650f9c&action=SMS&telnum=89991234567&smscontent=test&send=Send

Давайте разберем назначение этих параметров:

Реализация POST-запроса на современных платформах (1С 8.2 и 8.3)

Для начала разберем по шагам, как настроить отправку в современных версиях платформы 1С:Предприятие, где нам доступны полноценные объекты HTTPСоединение и HTTPЗапрос. Создадим процедуру, которая формирует строку параметров, преобразует ее в двоичные данные и отправляет на шлюз.


Процедура ОтправитьСМС_GoIP_83(НомерТелефона, ТекстСообщения, НомерКанала = "1")
    
    // Адрес нашего шлюза в локальной сети
    СерверШлюза = "192.168.1.190";
    Логин = "admin";
    Пароль = "admin";
    
    // Генерируем уникальный smskey для отслеживания статуса
    ТекВремя = ТекущаяДата() - Дата('00010101000000');
    ГСЧ = Новый ГенераторСлучайныхЧисел(ТекВремя);
    КлючСМС = Формат(ГСЧ.СлучайноеЧисло(10000000, 99999999), "ЧГ=0");
    
    // Формируем структуру параметров
    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("line", НомерКанала);
    ПараметрыЗапроса.Вставить("smskey", КлючСМС);
    ПараметрыЗапроса.Вставить("action", "SMS");
    ПараметрыЗапроса.Вставить("telnum", НомерТелефона);
    ПараметрыЗапроса.Вставить("smscontent", ТекстСообщения);
    ПараметрыЗапроса.Вставить("send", "Send");
    
    // Преобразуем параметры в URL-encoded строку
    СтрокаТела = "";
    Для Каждого Параметр Из ПараметрыЗапроса Цикл
        Если Не ПустаяСтрока(СтрокаТела) Тогда
            СтрокаТела = СтрокаТела + "&";
        КонецЕсли;
        СтрокаТела = СтрокаТела + Параметр.Ключ + "=" + КодироватьСтроку(Параметр.Значение, СпособКодированияСтроки.КодироватьИмена canBeEmpty);
    КонецЦикла;
    
    // Настраиваем соединение и запрос
    Соединение = Новый HTTPСоединение(СерверШлюза, , Логин, Пароль);
    
    АдресРесурса = "/default/en_US/sms_info.html?type=sms";
    
    Запрос = Новый HTTPЗапрос(АдресРесурса);
    Запрос.Заголовки.Вставить("Accept", "*/*");
    Запрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
    
    // Устанавливаем тело запроса в кодировке UTF-8
    Запрос.УстановитьТелоИзСтроки(СтрокаТела, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    Попытка
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);
        КодСостояния = Ответ.КодСостояния;
        Если КодСостояния = 200 Тогда
            Сообщить("Запрос успешно отправлен! Код ответа 200.");
        Иначе
            Сообщить("Ошибка отправки! Код состояния: " + КодСостояния);
        КонецЕсли;
    Исключение
        Сообщить("Не удалось связаться со шлюзом: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Адаптация решения под старую платформу 1С 8.1

Посмотрим на ситуацию, когда нам приходится работать в среде 1С 8.1. В этой версии платформы отсутствует объект HTTPЗапрос. Единственное, что у нас есть — это HTTPСоединение и его метод ОтправитьДляОбработки, который требует обязательного использования физических файлов на диске для передачи и приема данных. Рассмотрим, как правильно реализовать эту схему через дисковый кэш.


Процедура ОтправитьСМС_GoIP_81(НомерТелефона, ТекстСообщения, НомерКанала = "1")
    
    СерверШлюза = "192.168.1.190";
    Логин = "admin";
    Пароль = "admin";
    
    // Генерация ключа СМС
    КлючСМС = "81" + Формат(ТекущаяДата() - Дата('00010101000000'), "ЧГ=0");
    
    // Формирование строки запроса
    ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("line", НомерКанала);
    ПараметрыЗапроса.Вставить("smskey", КлючСМС);
    ПараметрыЗапроса.Вставить("action", "SMS");
    ПараметрыЗапроса.Вставить("telnum", НомерТелефона);
    // Обратите внимание: функция URLEncode81 должна корректно кодировать кириллицу в UTF-8 URL-формат!
    ПараметрыЗапроса.Вставить("smscontent", URLEncode81(ТекстСообщения));
    ПараметрыЗапроса.Вставить("send", "Send");
    
    СтрокаЗапроса = "";
    Для Каждого Параметр Из ПараметрыЗапроса Цикл
        Если Не ПустаяСтрока(СтрокаЗапроса) Тогда
            СтрокаЗапроса = СтрокаЗапроса + "&";
        КонецЕсли;
        СтрокаЗапроса = СтрокаЗапроса + Параметр.Ключ + "=" + Параметр.Значение;
    КонецЦикла;
    
    // Запись тела запроса во временный файл
    ИмяФайлаЗапроса = ПолучитьИмяВременногоФайла("txt");
    ФайлЗапроса = Новый ЗаписьТекста(ИмяФайлаЗапроса, КодировкаТекста.UTF8);
    ФайлЗапроса.Записать(СтрокаЗапроса);
    ФайлЗапроса.Закрыть();
    
    // Инициализация файла для получения ответа
    ИмяФайлаОтвета = ПолучитьИмяВременногоФайла("html");
    
    // Формируем заголовки HTTP в объекте Соответствие
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Accept", "*/*");
    Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
    
    Попытка
        Соединение = Новый HTTPСоединение(СерверШлюза, , Логин, Пароль);
        АдресРесурса = "/default/en_US/sms_info.html?type=sms";
        
        // В 1С 8.1 отправка выполняется так:
        Соединение.ОтправитьДляОбработки(ИмяФайлаЗапроса, АдресРесурса, ИмяФайлаОтвета, Заголовки);
        Сообщить("Запрос отправлен. Проверьте результат.");
    Исключение
        Сообщить("Ошибка при работе с HTTPСоединение: " + ОписаниеОшибки());
    КонецПопытки;
    
    // Очистка временных файлов
    Попытка
        УдалитьФайлы(ИмяФайлаЗапроса);
        УдалитьФайлы(ИмяФайлаОтвета);
    Исключение
    КонецПопытки;
    
КонецПроцедуры

Использование COM-объекта WinHttpRequest (Рекомендуемый способ для 1С 8.1)

Проанализируем более элегантную альтернативу для платформы 1С 8.1, которая избавляет нас от необходимости создавать временные файлы на жестком диске. Мы можем использовать системную службу Windows через COM-объект WinHttp.WinHttpRequest.5.1. Это решение работает быстрее и стабильнее, так как все манипуляции с телом запроса и ответом шлюза происходят непосредственно в оперативной памяти.


Процедура ОтправитьСМС_ЧерезCOM(НомерТелефона, ТекстСообщения, НомерКанала = "1")
    
    СерверШлюза = "192.168.1.190";
    АдресРесурса = "http://" + СерверШлюза + "/default/en_US/sms_info.html?type=sms";
    
    // Создаем COM-объект для работы с HTTP-запросами
    Попытка
        WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
    Исключение
        Сообщить("Не удалось создать объект WinHttp.WinHttpRequest.5.1: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // Установка кодировки UTF-8 для корректной работы с кириллицей
    WinHttp.Option(2, "utf-8");
    
    // Открываем синхронное соединение (Ложь - синхронно)
    WinHttp.Open("POST", АдресРесурса, Ложь);
    
    // Настройка базовой авторизации на шлюзе
    WinHttp.SetCredentials("admin", "admin", 0); // 0 означает HTTP-авторизацию
    
    // Добавляем обязательные HTTP-заголовки
    WinHttp.SetRequestHeader("Accept", "*/*");
    WinHttp.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // Генерируем уникальный ключ
    КлючСМС = "COM" + Формат(ТекущаяДата() - Дата('00010101000000'), "ЧГ=0");
    
    // Текст сообщения должен быть закодирован в UTF-8 URL-Format
    КодированныйТекст = URLEncode81(ТекстСообщения);
    
    // Собираем тело запроса
    ТелоЗапроса = "line=" + НомерКанала + "&smskey=" + КлючСМС + "&action=SMS&telnum=" + НомерТелефона + "&smscontent=" + КодированныйТекст + "&send=Send";
    
    Попытка
        // Отправляем сформированное тело запроса
        WinHttp.Send(ТелоЗапроса);
        
        // Получаем ответ шлюза в виде текста
        ОтветСервера = WinHttp.ResponseText;
        Сообщить("Ответ шлюза: " + ОтветСервера);
    Исключение
        Сообщить("Ошибка при отправке POST-запроса через COM: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Как правильно закодировать кириллицу в 1С 8.1 (Функция URLEncode)

Разберем важный нюанс. Поскольку в старой версии 1С 8.1 нет встроенной функции КодироватьСтроку, нам необходимо написать собственный транслятор символов в URL-формат (Percent-encoding). Шлюз GoIP 4 ожидает получить текст СМС исключительно в кодировке UTF-8. Если мы просто передадим текст в системной кодировке Windows-1251, получатель увидит на телефоне нечитаемые символы.

Ниже приведен пример функции, которая преобразует строку в URL-совместимый вид с перекодированием в UTF-8 через использование COM-объекта ADODB.Stream:


Функция URLEncode81(СтрокаИсточника)
    
    Если ПустаяСтрока(СтрокаИсточника) Тогда
        Возврат "";
    КонецЕсли;
    
    // Используем ADODB.Stream для получения UTF-8 представления текста
    Поток = Новый COMОбъект("ADODB.Stream");
    Поток.Type = 2; // Текстовый
    Поток.Charset = "utf-8";
    Поток.Open();
    Поток.WriteText(СтрокаИсточника);
    Поток.Position = 0;
    Поток.Type = 1; // Переводим в бинарный режим
    
    ДвоичныеДанные = Поток.Read();
    Поток.Close();
    
    // Преобразуем полученные байты в шестнадцатеричный вид с процентами
    Результат = "";
    Для Поз = 1 По ДвоичныеДанные.Размер Цикл
        Байт = ДвоичныеДанные.Получить(Поз - 1);
        
        // Проверяем, является ли символ безопасным (ASCII-символы)
        Если (Байт >= 48 И Байт <= 57) // 0-9
            Или (Байт >= 65 И Байт <= 90) // A-Z
            Или (Байт >= 97 И Байт <= 122) Тогда // a-z
            Результат = Результат + Символ(Байт);
        ИначеЕсли Байт = 32 Тогда // Пробел
            Результат = Результат + "+";
        Иначе
            // Кодируем байт в формат %XX
            Результат = Результат + "%" + DecToHex(Байт);
        КонецЕсли;
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

Функция DecToHex(Знач Число)
    База = "0123456789ABCDEF";
    Результат = "";
    Пока Число > 0 Цикл
        Остаток = Число % 16;
        Результат = Сред(База, Остаток + 1, 1) + Результат;
        Число = Цел(Число / 16);
    КонецЦикла;
    Если СтрДлина(Результат) < 2 Тогда
        Результат = "0" + Результат;
    КонецЕсли;
    Возврат Результат;
КонецФункции

Получение статуса доставки отправленных сообщений

После того как мы успешно освоили отправку POST-запросов, разберем по шагам, как отслеживать статус доставки СМС. Шлюзы серии GoIP предоставляют специальный интерфейс для проверки состояния отправки через XML-документ send_status.xml.

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

http://192.168.1.190/default/en_US/send_status.xml?u=admin&p=admin

Рассмотрим типичную структуру XML-файла, который возвращает шлюз:


<?xml version="1.0" encoding="utf-8"?>
<send-sms-status>
    <id1>COM15829104</id1>
    <status1>DONE</status1>
    <error1></error1>
    <id2></id2>
    <status2>IDLE</status2>
    <error2></error2>
</send-sms-status>

Здесь суффиксы элементов (id1, status1) соответствуют номеру активного канала шлюза. Значения статусов могут быть следующими:

Важное архитектурное ограничение шлюза: Помните, что в файле send_status.xml сохраняются сведения только о самом последнем отправленном сообщении по каждой линии. Если вы отправите второе сообщение на линию 1 до того, как считаете статус первого, данные первого сообщения будут безвозвратно перезаписаны. Для надежной массовой рассылки отправляйте следующее сообщение на конкретный канал только после того, как текущее примет статус DONE или ERROR.

← На главную