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

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

При развертывании мобильных приложений 1С разработчики часто сталкиваются со следующей проблемой: внутри офиса мобильные устройства сотрудников подключаются к локальной Wi-Fi сети, однако опубликованный веб-сервер 1С доступен изнутри только по локальному IP-адресу (например, http://192.168.3.73/), а снаружи — только по внешнему статическому IP или доменному имени (например, https://MyApp.MyCompany.ru:8888/). Попытка подключиться по внешнему адресу, находясь внутри офисного Wi-Fi, приводит к ошибке соединения. Это происходит из-за особенностей маршрутизации, когда локальный роутер не умеет перенаправлять внутренний трафик обратно на себя по внешнему IP-адресу.

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

Вариант 1. Системное решение на стороне сети (Без изменения кода 1С)

Это самый надежный, профессиональный и безопасный подход. Если настроить сеть правильно, то мобильное приложение 1С сможет работать по одному и тому же внешнему адресу как из мобильного интернета (или домашнего Wi-Fi), так и находясь в офисной локальной сети.

Рассмотрим два основных способа реализации этой схемы на сетевом оборудовании:

  1. Настройка NAT Loopback (или Hairpin NAT).

    Эта функция настраивается системным администратором на офисном маршрутизаторе (например, MikroTik, Cisco, Keenetic). Суть механизма заключается в том, что когда устройство из локальной сети обращается к внешнему IP-адресу своего же роутера, роутер распознает этот трафик и перенаправляет его обратно на внутренний IP-адрес сервера 1С. Для мобильного клиента этот процесс происходит абсолютно бесшовно.

    Если ваши администраторы ссылаются на то, что это невозможно сделать из-за разных портов (например, внешний порт 8888 перенаправляется на внутренний 80), то правильным решением будет убрать подмену портов. Сделайте так, чтобы веб-сервер 1С внутри сети также слушал тот же порт (или настройте редирект внутри сети через обратный прокси-сервер, например, Nginx).

  2. Использование технологии Split-Brain DNS (Split DNS).

    Этот метод основан на разграничении зон видимости DNS-имен. Суть в том, что доменное имя вашей публикации MyApp.MyCompany.ru на внешних DNS-серверах (в глобальном интернете) указывает на ваш внешний статический IP-адрес. В то же время на локальном DNS-сервере офиса (например, поднятом на контроллере домена Active Directory) настраивается зона, в которой это же имя MyApp.MyCompany.ru указывает на внутренний IP-адрес сервера 1С — 192.168.3.73.

    Когда сотрудник находится дома или в дороге, его устройство запрашивает IP у публичного DNS и получает внешний адрес. Когда сотрудник подключается к офисному Wi-Fi, локальный DNS-сервер выдает устройству локальный IP-адрес. В итоге в настройках мобильного приложения всегда прописан один красивый адрес https://MyApp.MyCompany.ru.

Вариант 2. Быстрый последовательный опрос адресов (Ping с таймаутом в 1С)

Если системные администраторы наотрез отказываются идти навстречу, нам придется решать задачу на стороне мобильного приложения 1С. Один из самых простых и надежных способов — быстрая проверка доступности локального адреса перед началом синхронизации.

Мы можем реализовать функцию, которая отправляет легкий запрос к веб-серверу с очень маленьким временем ожидания (таймаутом). Если локальный сервер ответил быстро — работаем по локальному адресу. Если произошел таймаут или вернулась ошибка — переключаемся на глобальный адрес.

Разберем пример кода на встроенном языке 1С, реализующий этот алгоритм:


Функция ОпределитьРабочийАдресПубликации() Экспорт

    ЛокальныйАдрес  = "192.168.3.73";
    ГлобальныйАдрес = "MyApp.MyCompany.ru";
    ЛокальныйПорт   = 80;
    ГлобальныйПорт  = 8888;
    
    // Пытаемся быстро подключиться к локальному серверу.
    // Устанавливаем таймаут в 1-2 секунды, чтобы пользователь не ждал долго.
    Если ПроверитьДоступностьХоста(ЛокальныйАдрес, ЛокальныйПорт, 2) Тогда
        Возврат "http://" + ЛокальныйАдрес + "/MyApp/ws/MobileAppExchange";
    КонецЕсли;
    
    // Если локальный адрес недоступен, предполагаем, что мы во внешней сети
    Если ПроверитьДоступностьХоста(ГлобальныйАдрес, ГлобальныйПорт, 5) Тогда
        Возврат "https://" + ГлобальныйАдрес + ":" + Формат(ГлобальныйПорт, "ЧГ=0") + "/MyApp/ws/MobileAppExchange";
    КонецЕсли;
    
    // Если оба адреса недоступны
    ВызватьИсключение "Не удалось установить соединение с сервером 1С. Проверьте подключение к сети.";

КонецФункции

Функция ПроверитьДоступностьХоста(Знач Хост, Знач Порт, Знач Таймаут)
    
    // Используем HTTPСоединение для быстрой проверки
    // Нам не важно получить данные, главное - проверить сам факт соединения
    Попытка
        Соединение = Новый HTTPСоединение(Хост, Порт, , , , Таймаут);
        Запрос = Новый HTTPЗапрос("/MyApp/ws/MobileAppExchange?wsdl");
        Ответ = Соединение.Получить(Запрос);
        
        // Коды 200 (ОК) или 401 (Требуется авторизация) подтверждают, что сервер ответил
        Если Ответ.КодСостояния = 200 Или Ответ.КодСостояния = 401 Тогда
            Возврат Истина;
        КонецЕсли;
    Исключение
        // Исключение сработает по истечении таймаута или при отсутствии маршрута
        Возврат Ложь;
    КонецПопытки;
    
    Возврат Ложь;

КонецФункции

Важный нюанс: метод HTTPСоединение с таймаутом отлично работает на мобильной платформе 1С. Использование короткого таймаута в 2 секунды гарантирует, что при нахождении вне офиса приложение не будет "зависать" надолго при попытке простучать локальный IP.

Вариант 3. Определение по внешнему IP-адресу (Метод автора темы)

Еще один оригинальный программный способ заключается в сопоставлении текущего внешнего IP-адреса мобильного устройства со статическим IP-адресом офисного шлюза.

Когда устройство подключено к офисному Wi-Fi, весь его трафик идет в интернет через один общий офисный роутер, который имеет вполне конкретный статический внешний IP-адрес (например, 193.242.149.149). Мы можем выполнить быстрый GET-запрос к любому публичному API, возвращающему IP-адрес клиента, и сравнить результат.

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


Функция УстройствоВЛокальнойСетиОфиса() Экспорт

    СтатическийОфисныйIP = "193.242.149.149"; // Внешний IP вашей организации
    
    // Используем бесплатный и быстрый сервис для определения внешнего IP
    ХостСервиса = "api.ipify.org";
    
    Попытка
        Соединение = Новый HTTPСоединение(ХостСервиса, , , , , 3);
        Запрос = Новый HTTPЗапрос("/?format=json");
        Ответ = Соединение.Получить(Запрос);
        
        Если Ответ.КодСостояния = 200 Тогда
            // Читаем полученный JSON ответ
            ЧтениеJSON = Новый ЧтениеJSON;
            ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
            Данные = ПрочитатьJSON(ЧтениеJSON);
            ЧтениеJSON.Закрыть();
            
            ТекущийВнешнийIP = Данные.ip;
            
            // Если внешний IP устройства совпадает с офисным, значит мы подключены к офисному Wi-Fi
            Если ТекущийВнешнийIP = СтатическийОфисныйIP Тогда
                Возврат Истина;
            КонецЕсли;
        КонецЕсли;
    Исключение
        // Если сервис определения IP недоступен, возвращаем Ложь и пробуем глобальный адрес по умолчанию
        Возврат Ложь;
    КонецПопытки;
    
    Возврат Ложь;

КонецФункции

Если функция УстройствоВЛокальнойСетиОфиса() возвращает Истина, мобильное приложение 1С сразу использует для подключения локальный адрес публикации http://192.168.3.73/.... Если возвращается Ложь (например, пользователь сидит на домашнем Wi-Fi со своим внешним IP или использует мобильные сотовые данные) — приложение подключается по внешнему адресу.

Вариант 4. Нахождение SSID сети через внешнюю компоненту 1С

Стандартный метод мобильной платформы ИнформацияОбИнтернетСоединении.ПолучитьТипСоединения() возвращает системное перечисление ТипИнтернетСоединения.WiFi, но не дает детальной информации о том, к какой именно беспроводной точке подключено устройство.

Чтобы программно вытащить имя сети (SSID), можно использовать технологию создания внешних компонент (Native API) для Android и iOS. Написанная на Java или Kotlin компонента для Android может легко обратиться к системным службам операционной системы:

WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifiManager.getConnectionInfo();
String ssid = info.getSSID();

Однако при использовании данного метода следует учитывать жесткие ограничения современных версий мобильных ОС (Android 9+ и iOS 13+): для получения SSID приложение обязано запросить у пользователя явное разрешение на доступ к точной геолокации (ACCESS_FINE_LOCATION), а на самом устройстве в момент проверки должен быть включен GPS-приемник. В противном случае операционная система в целях безопасности вернет пустую строку или значение <unknown ssid>. Из-за этих ограничений данный способ является наименее предпочтительным и сложным в поддержке.

Резюме и рекомендации

Подводя итоги, расположим решения в порядке убывания их правильности и удобства для бизнеса:

  1. Лучший выбор: Настоятельно рекомендуем провести переговоры с ИТ-отделом и настроить на шлюзе Hairpin NAT (NAT Loopback) или поднять локальную зону Split DNS. Это полностью избавит вас от необходимости писать лишний код в 1С и исключит любые проблемы с портами и протоколами шифрования (SSL/HTTPS).
  2. Запасной вариант (в коде 1С): Если изменить настройки сети невозможно, реализуйте в мобильном приложении метод последовательного опроса хостов (Вариант 2). Он автономен, не зависит от сторонних интернет-сервисов (в отличие от проверки внешнего IP) и обеспечивает быстрое переключение адресов незаметно для конечного пользователя.
← На главную