VPN оборвался посреди страницы: уходят ли ещё фоновые запросы?
Оставленная открытой страница продолжает опрашивать, переподключаться и синхронизироваться после смерти туннеля. Посмотрите, какие попытки всё ещё уходят и как это доказать.
Вкладка всё ещё показывает панель управления с тех пор, как туннель был жив. Цифры состояния замирают, маленький индикатор продолжает крутиться, а в адресной строке всё ещё то приложение, которое вы открыли час назад. После обрыва вы ничего не трогали, и всё же страница, возможно, всё ещё пытается достучаться до своего сервера по собственному расписанию. Именно это люди упускают: страница, которая лишь видна, и страница, которая всё ещё отправляет запросы, снаружи выглядят одинаково, и только одна из них попадает в сетевой журнал.
Работа, которую страница начинает без вас
Четыре механизма держат загруженный документ занятым. Повторяющийся таймер может заново запускать вызов состояния каждые несколько секунд. Fetch может сработать, когда вкладка снова становится видимой после возврата к ней. Живой канал на основе WebSocket или событий, отправляемых сервером, может пытаться переподключиться по собственному графику отступления. Service worker, зарегистрированный сайтом, может проснуться для синхронизации в очереди, даже когда перед вами нет ни одной вкладки.
Ни одному из них не нужен клик, и ни один не перезагружает документ. Адресная строка, позиция прокрутки и отрисованные значения остаются на месте. Меняется только сетевая сторона: каждая новая попытка — это свежее решение, принятое в момент её начала.
Это различие важно, потому что видимая страница хранится локально. Уже нарисованные пиксели ничего не говорят о том, удался ли следующий запрос. Замёрзший график с индикатором — обычный вид страницы, запросы которой сейчас терпят неудачу. Чтение экрана говорит вам, что сервер сказал несколько минут назад, а не что браузер делает сейчас.
Почему прежняя загрузка страницы не удерживает маршрут
Ничто в загрузке страницы не привязывает документ к туннелю. Маршрутизация определяется для каждого пакета в момент отправки по таблице, которая существует, когда пакет уходит. Когда интерфейс туннеля исчезает, этот поиск больше не совпадает с маршрутом туннеля. Он либо проваливается на физический адаптер, либо не находит ничего, в зависимости от того, что оставил клиент.
Повторяющиеся обратные вызовы — обычные запланированные задачи. Раздел стандарта HTML о таймерах описывает, как они ставятся в очередь, и трактует интервал как минимальную задержку, а не обещание точного ритма, поэтому фоновая вкладка может опрашивать гораздо реже, чем просит её код. Меньше попыток — не то же самое, что ни одной попытки, а возвращение вкладки на передний план — обычный момент для их всплеска.
Куда приземляется политика отказа
Блокировка клиента оценивается тогда, когда предпринимается попытка соединения, а не тогда, когда страница была получена. Если обычный доступ всё ещё разрешён, повторная попытка может уйти через физический канал в открытом виде. Если политика удерживает этот трафик до возвращения туннеля, попытка терпит неудачу в момент подключения, и страница показывает ошибку, которую можно повторить через несколько секунд.
Две детали решают, что именно вы получите. Первая — область применения, которую поддерживает клиент: блокировка всего устройства, блокировка только адаптера туннеля или набор правил с исключениями. Вторая — попадает ли адресат в исключение, добавленное ранее для локального принтера, пленённого портала или стримингового сервиса.
Шифрование на уровне приложения ничего из этого не меняет. HTTPS защищает байты между браузером и сервером; он ничего не говорит о том, какой интерфейс их несёт. Страница может быть идеально зашифрована и всё равно уходить не тем путём, и именно это позволяет узкая блокировка.
Контролируемая проверка на одноразовой странице
Возьмите хост, который вы контролируете, и страницу, которая не делает ничего, кроме вызова к нему, чтобы в игре не было реальных данных. Из терминала снимите образец пути до и после обрыва:
curl -sS --max-time 5 -o /dev/null -w '%{http_code} %{remote_ip}\n' https://probe.example.net/pingЗапустите это с поднятым туннелем, затем опустите туннель и запустите снова. Ответ с публичного адреса при опущенном туннеле говорит, что прямой путь открыт. Истёкшее время ожидания или отказ в соединении говорит, что политика держит. Повторите ещё раз после того, как клиент переподключится, чтобы увидеть возвращение пути через туннель, а не предполагать его.
В браузере панель «Сеть» разделяет эти два вопроса. Отфильтруйте по Fetch/XHR, затем прочитайте столбец инициатора: запись, запущенная таймером или скриптом, без зафиксированного перед ней перехода, — это фоновая попытка, а не перезагрузка. Сравните время её начала с моментом обрыва туннеля. Если запись всё ещё в ожидании, когда туннель исчез, запрос ждёт пути, которого больше нет.
Доказательства на стороне сервера сильнее всего, что показывает браузер. Журнал запросов с отметкой времени и адресом источника доказывает, что пакет пришёл. Записи браузера могут нести cookie, токены и полные URL-адреса, поэтому оставьте только поля, нужные вашему вопросу, и скройте остальное, прежде чем вставлять их куда-либо.
Что делать с ответом
Если фоновые попытки продолжают удаваться при опущенном туннеле, блокировка уже, чем вы предполагали, и эту щель стоит закрыть, прежде чем доверять клиенту чувствительную работу. Если они терпят неудачу, политика делает свою работу, а замёрзшая страница — только оформление. Так или иначе, закрытие одной вкладки не является контролем на уровне всего устройства: другие вкладки, другие браузеры и другие приложения каждое планирует свою работу.
Шаги, которые стоит сделать: перечислите, какие исключения вы добавили и почему, подтвердите, блокирует ли клиент только трафик в области туннеля или весь трафик, и проследите один фоновый запрос от начала до конца с открытым журналом сервера. Эти три ответа покрывают большую часть того, что на самом деле содержит отчёт «VPN оборвался, а что-то всё ещё подключено».