Opt-In Software Blog

Software, dvelopment, and practical insights

WebSocket Session API in ProxyMapService

Читать на другом языке: English | Русский

Мониторинг трафика в реальном времени: реализация WebSocket API для подписок в ProxyMapService

Часто в приложениях веб-скрапинга необходимо оперативно получать информацию обо всех URL-адресах, которые скачиваются в данный момент. 

Однако на практике это может оказаться далеко не тривиальной задачей. Например, если целевое приложение — браузер, для перехвата сетевой активности обычно требуется глобально переопределить встроенные методы fetch и XHR (XMLHttpRequest). Ситуация сильно усложняется, если на веб-странице присутствуют элементы iframe: в них также необходимо динамически внедрять переопределения для fetch и XHR, что добавляет дополнительный уровень сложности и хрупкости всей системе. Кастомные скрипты могут конфликтовать с политиками безопасности (Content Security Policy) или просто пропускать запросы из изолированных контекстов. 

Вместо того чтобы ломать логику внутри самого браузера и внедрять сложные инъекции, гораздо надежнее использовать возможности прокси-слоя. Для этого в ProxyMapService было реализовано опциональное WebSocket Session API. Оно позволяет внешним приложениям подключаться напрямую к прокси, передавать нужный фильтр URL и мгновенно получать push-сообщения обо всех запрашиваемых ресурсах. 

Конфигурация и особенности подключения

За работу данного механизма отвечает раздел SessionAPI в файле конфигурации appsettings.json. Вот как он выглядит по умолчанию: 

"SessionAPI": {
    "Enabled": false,
    "WebSocketsEnabled": false,
    "Domain": ""
}

Как можно видеть, по умолчанию вся инфраструктура SessionAPI, включая веб-сокеты, отключена, а свойство Domain оставлено пустым. 

Вариант 1. Работа через локальный порт (Пустой домен)

Если Domain пустой, доступ к управляющим эндпоинтам осуществляется как к обычному веб-серверу на одном из портов, которые ProxyMapService слушает для входящих соединений. Например, если прокси запущен на порту 5000: 

  • Доступ к HTTP API: http://127.0.0.1:5000/session/
  • Настройка браузера: в качестве HTTP или SOCKS5 прокси указывается 127.0.0.1:5000.

Вариант 2. Работа через выделенный псевдо-домен (Рекомендуемый)

Для полноценной изоляции управляющего трафика от проксируемого рекомендуется включить API и задать специальный внутренний домен: 

"SessionAPI": {
    "Enabled": true,
    "WebSocketsEnabled": true,
    "Domain": "proxymapper"
}

В этом режиме proxymapper становится выделенным системным доменом. Когда ProxyMapService видит, что клиент обращается к хосту proxymapper, он перехватывает этот запрос локально и обрабатывает его как вызов к SessionAPI, вместо того чтобы проксировать его во внешнюю сеть. 

Важный нюанс для консольных утилит (например, cURL):

Если вы используете curl для работы с прокси, протокол socks4 вообще не позволит вызвать внутреннее API. Более того, вместо стандартного префикса socks5:// нужно использовать socks5h:// (например, socks5h://127.0.0.1:5000). Это необходимо для того, чтобы curl не пытался самостоятельно отресолвить домен proxymapper через DNS вашей операционной системы, а делегировал разрешение этого имени самому прокси-серверу. 

При такой конфигурации вызов WebSocket Session API будет осуществляться через веб-сокет по адресу: ws://proxymapper/session/ws

Как это работает на практике

Использование механизма подписок выглядит так: 

  1. Установка соединения: Клиент открывает постоянное WebSocket-соединение по адресу ws://proxymapper/session/ws.
  2. Передача фильтра: Сразу после успешного подключения клиент отправляет текстовое JSON-сообщение с действием subscribe и регулярным выражением (Regex) для интересующих его URL:

 

{
  "action": "subscribe",
  "pattern": "api\\.example\\.com/v1/.*"
}
  1. Подтверждение подписки и session_id: В ответ сервер присылает подтверждение успешной регистрации фильтра, которое содержит важный контекст:

 

{
  "status": "subscribed",
  "session_id": ":5000"
}

Что означает session_id и как работает изоляция трафика? 

  • session_id — это уникальный идентификатор сессии. Если в вашем окружении используется авторизация через Sticky Proxy, этот строковый идентификатор явно привязывается к пользователю в момент аутентификации.
  • Если же Sticky Proxy не используется, то в качестве session_id возвращается двоеточие, за которым следует номер входящего порта (например, :5000). Это означает, что уведомления жестко изолированы конкретным портом, через который была оформлена подписка.
  • Важное правило жизненного цикла: Пользователь гарантированно получает уведомления об URL-адресах, скачиваемых строго в рамках той сессии, которая была активна на момент подписки. Если сессия на прокси сменилась, уведомления по старой подписке приходить перестанут. Точно так же, при изоляции портами (без sticky), вы никогда не увидите в веб-сокете порта :5000 трафик, проходящий параллельно через другой настроенный порт прокси.
  1. Получение уведомлений: При совпадении скачиваемого URL с вашей маской прокси-сервер отправляет плоское структурированное событие, оптимизированное для быстрого чтения:

 

{
  "event_type": "url_matched",
  "timestamp": "2026-09-02T10:20:45.0328755Z",
  "session_id": ":5000",
  "method": "GET",
  "url": "https://api.example.com/v1/users/profile"
}

Окружение для тестирования: Proxy WebSocket Control Panel

Тестовая веб-панель размещена в выделенной поддиректории проекта: tests\test-websocket.

Внутри папки находится автономный HTML-файл index.html, реализующий диагностический интерфейс: 

<!-- Located at: \tests\test-websocket\index.html -->
<div class="card">
    <h2>Proxy WebSocket Control Panel</h2>
    <div class="form-group">
        <input type="text" id="wsUrl" value="ws://proxymapper/session/ws">
        <button onclick="toggleConnection()">Connect</button>
    </div>
    <div class="form-group">
        <input type="text" id="filterPattern" value="(google\.com|yandex\.ru)/.*">
        <button onclick="sendSubscription()">Set Filter</button>
    </div>
</div>

Как запустить тест и проверить мониторинг:

  1. Запустите настроенный ProxyMapService с включенными веб-сокетами и доменом proxymapper.
  2. Откройте файл tests\test-websocket\index.html в любом современном браузере, трафик которого идет через ваш прокси.
  3. Нажмите кнопку Connect, задайте регулярное выражение для фильтрации и наблюдайте, как в темную консоль интерфейса мгновенно прилетают уведомления со всеми деталями перехваченных запросов.

Заключение

Вынесение логики трейсинга URL из кастомных скриптов браузера на уровень ProxyMapService позволило увидеть все сетевые запросы. Теперь не важно, откуда уходит запрос — из основного окна, тяжелого iframe или вообще из фонового сервис-воркера — прокси-сервер гарантированно перехватит его, отфильтрует с учетом активной сессии (или порта) и безопасно доставит клиенту через WebSocket-подписку без изменения оригинального кода страниц.

Search