Рассылка СМС-уведомлений — неотъемлемая часть современных корпоративных систем. Зачастую для этих целей используется специализированное оборудование, такое как VoIP-шлюзы GoIP. В этой статье мы подробно разберем, как реализовать отправку СМС-сообщений через четырехканальный шлюз GoIP 4 из среды «1С:Предприятие». Мы проанализируем различные подходы, начиная от простых GET-запросов и заканчивая сложными POST-запросами с обработкой статусов доставки. Особое внимание уделим адаптации кода под старые версии платформы, такие как 1С 8.1, где отсутствуют многие современные объекты для работы с веб-службами.
Выясним причину, почему разработчики часто стремятся перейти с простых GET-запросов на POST. На первый взгляд, GET-запрос выглядит гораздо проще: в 1С его реализация занимает буквально несколько строк кода. Однако у GET-запросов есть существенные недостатки:
Рассмотрим подробнее, как именно шлюз GoIP ожидает получить данные. Часто разработчики допускают ошибку, пытаясь передать тело запроса в формате JSON. Проанализировав поведение веб-интерфейса шлюза GoIP 4 (например, через консоль разработчика в браузере), мы можем увидеть, что устройство работает со стандартной формой кодирования данных application/x-www-form-urlencoded.
Это означает, что тело нашего POST-запроса должно представлять собой строку параметров, соединенных символом амперсанда &, где каждый параметр закодирован в URL-формат.
Типичная строка запроса выглядит следующим образом:
line=1&smskey=5c650f9c&action=SMS&telnum=89991234567&smscontent=test&send=Send
Давайте разберем назначение этих параметров:
line — номер GSM-линии (канала) шлюза (от 1 до 4 в случае GoIP 4), через которую будет отправлено сообщение. Также можно использовать синтаксис вида line1=1.smskey — уникальный идентификатор сообщения (произвольный ключ, генерируемый вашей системой). Он критически важен для последующего отслеживания статуса доставки СМС.action — тип действия. Для отправки СМС всегда передается значение "SMS".telnum — номер телефона получателя СМС-сообщения.smscontent — текст СМС-сообщения, предварительно закодированный в URL-формат.send — системный параметр, инициирующий отправку (передается значение "Send").Для начала разберем по шагам, как настроить отправку в современных версиях платформы 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. В этой версии платформы отсутствует объект 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Соединение: " + ОписаниеОшибки());
КонецПопытки;
// Очистка временных файлов
Попытка
УдалитьФайлы(ИмяФайлаЗапроса);
УдалитьФайлы(ИмяФайлаОтвета);
Исключение
КонецПопытки;
КонецПроцедуры
Проанализируем более элегантную альтернативу для платформы 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 нет встроенной функции КодироватьСтроку, нам необходимо написать собственный транслятор символов в 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) соответствуют номеру активного канала шлюза. Значения статусов могут быть следующими:
STARTED — сообщение находится в очереди на отправку мобильным оператором.DONE — СМС успешно отправлено в сотовую сеть.ERROR — произошел сбой при отправке (например, отсутствует сигнал сотовой связи или исчерпан баланс SIM-карты).Важное архитектурное ограничение шлюза: Помните, что в файле send_status.xml сохраняются сведения только о самом последнем отправленном сообщении по каждой линии. Если вы отправите второе сообщение на линию 1 до того, как считаете статус первого, данные первого сообщения будут безвозвратно перезаписаны. Для надежной массовой рассылки отправляйте следующее сообщение на конкретный канал только после того, как текущее примет статус DONE или ERROR.