Идентичность

Жизненный цикл и приватность кеша сервис-воркера

Как регистрация, установка, активация и обновление сервис-воркера определяют владельца каждого кеша и как версионировать его, чистить и очищать при выходе из аккаунта.

Документация

Нужна структурированная документация по теме Идентичность?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

Почему у кеша сервис-воркера должен быть владелец

Сервис-воркер позволяет сайту отвечать на сетевые запросы из локального хранилища, обычно CacheStorage. Это полезно для офлайн-страниц и более быстрых повторных визитов. Но это значит и то, что ответ может пережить страницу, визит, а иногда и аккаунт, из-за которого он был сохранён. Спецификация Service Workers описывает worker и его жизненный цикл, а справочник CacheStorage на MDN описывает именованные кеши, которые могут открывать worker или страница.

CacheStorage принадлежит источнику (origin), а не конкретной версии worker. Кеш, созданный старым worker, остаётся на месте, когда управление переходит к новому, и ничто его не удалит, если код приложения не удалит его сам, если браузер не вытеснит данные при нехватке места или если пользователь либо ответ с Clear-Site-Data не очистит данные сайта. Момент вытеснения различается между браузерами и версиями, поэтому считайте его страховкой, а не планом очистки.

Схема жизненного цикла с этапами регистрации, установки, ожидания, активации и запросов; версионированный кеш создаётся при установке, старые кеши удаляются при активации, а кеши аккаунта очищаются при выходе

Поэтому практический вопрос касается владения. Для каждого кеша команда должна уметь сказать, какая версия worker его создала, какой релиз вправе его удалить и какой сессии или аккаунту пользователя принадлежит его содержимое. Кеш без названного владельца остаётся кешем, который никто не очистит.

Представьте общий планшет на стойке обслуживания. Сотрудники входят в аккаунт, открывают панель и выходят в конце смены. Если worker сохранял привязанные к аккаунту ответы API, пока они работали, следующий человек, открывший панель, может найти эти ответы в хранилище браузера, хотя интерфейс показывает состояние «вход не выполнен». Этот сбой никак не проявляется на экране, поэтому его легко упустить. Та же картина встречается на семейных компьютерах, в киосках и в любом профиле браузера, которым со временем пользуются несколько аккаунтов.

CacheStorage к тому же лишь одно из мест, где сайт хранит состояние. HTTP-кеш браузера, cookie, localStorage, IndexedDB и регистрации сервис-воркеров образуют отдельные хранилища с отдельными путями очистки. Очистка одного не очищает остальные. Когда проверка выясняет, что осталось после выхода, она должна перечислить каждое хранилище, которым пользуется приложение, и проверить их по одному, а не делать вывод по единственному пустому списку, что устройство чисто.

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

Этапы жизненного цикла

Страница просит браузер зарегистрировать worker для некоторой области действия (scope). Браузер загружает скрипт и выполняет этап установки. Worker, установленный в то время, когда более старый worker ещё управляет открытыми страницами, переходит в состояние ожидания, пока эти страницы не закроются или пока приложение не решит пропустить ожидание. Затем выполняется этап активации, и с этого момента worker обрабатывает события fetch страниц, которыми управляет. Руководство web.dev по жизненному циклу разбирает эти этапы на примерах.

Обновления определяются самим скриптом. Когда браузер видит, что скрипт worker отличается от установленного, он устанавливает новую версию рядом со старой, а не заменяет её на месте. Как часто браузер проверяет, изменился ли скрипт, зависит от навигации, функциональных событий и собственной политики браузера, поэтому при выкладке нельзя предполагать, что каждый пользователь получит новый worker в предсказуемый момент.

Поэтому новый worker может быть установлен, но не работать. Проверяющий, который видит новый скрипт на сервере, не может заключить, что тот уже обслуживает страницы. Worker бывает активным, ожидающим или замещённым, и проверка должна считывать это состояние, а не предполагать его. События, о которых идёт речь, описаны в руководстве Using Service Workers.

Два вызова меняют поведение ожидания и требуют осознанного решения. Пропуск этапа ожидания заставляет новый worker активироваться немедленно, а захват клиентов позволяет ему взять под контроль страницы, открытые до него. Оба приёма могут подойти для небольшого исправления, но они же означают, что открытая страница, загрузившая старые скрипты, может начать получать ответы из кеша, подготовленного для нового релиза. Если старая страница и новый кеш несовместимы, пользователь видит сломанное поведение, которого нет ни в одном релизе по отдельности. Записывайте, пропускает ли приложение ожидание и как это влияет на открытые страницы.

Область регистрации тоже важна. Worker управляет только страницами внутри своей области, а страницы одного источника совместно имеют доступ к одним и тем же записям кеша. Поэтому кеш, заполненный одним worker, могут прочитать страницы, которыми этот worker не управляет, и это ещё одна причина называть каждый кеш и его владельца.

На этапе fetch worker решает, что отдавать. Статические ресурсы, которые меняются только с релизом, подходят для подхода «сначала кеш», потому что метка версии уже управляет свежестью. Персонализированные страницы и ответы API обычно подходят для подхода «сначала сеть», а некоторые не следует сохранять вообще. Если описывать стратегию по категориям запросов, а не одним правилом для сайта в целом, последующее правило очистки получается проще, потому что каждой категории соответствует кеш с известным владельцем и известным сроком жизни.

Выложенное обновление можно наблюдать, а не угадывать. Инструменты разработчика показывают зарегистрированный worker, адрес его скрипта и то, ожидает ли более новая версия. После релиза загрузите приложение в свежем контексте, прочитайте эту панель и отметьте состояние в записи о релизе. Если сообщается об ожидающем worker, решите, ждать ли закрытия страниц, предложить ли пользователю перезагрузить страницу или пропустить ожидание, и запишите это решение.

Версионированные кеши и очистка при активации

Давайте каждому кешу имя с меткой версии, например префикс для оболочки приложения и следом метку релиза. Создавайте новый версионированный кеш и заполняйте его на этапе установки: именно тогда новый worker готовит собственные ресурсы, пока старый продолжает отдавать страницы из старого кеша.

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

Удаляйте старые кеши на этапе активации. Активация наступает, когда старый worker уже не нужен, а удаление его кеша раньше может сломать страницы, которые ещё работают. Типичное правило перечисляет имена кешей, оставляет те, что соответствуют текущему релизу, и удаляет остальные. Запишите это правило, чтобы проверяющий мог его проверить.

Будьте внимательны к тому, какие имена правило очистки вправе удалять. CacheStorage общее для источника целиком, поэтому список имён кешей может включать кеши, созданные другим кодом того же источника, например старым worker для другой функции. Ограничьте удаление именами, которые начинаются с вашего собственного префикса. Помните и о том, что неудачный запрос при заполнении нового кеша на этапе установки может вообще не дать новому worker установиться, и тогда старый worker и его кеш остаются на месте. Проверяйте состояние worker после релиза, а не считайте, что установка завершилась.

CacheStorage сам по себе не применяет правила свежести HTTP. Запись остаётся, пока код её не удалит, поэтому устаревший ответ может продолжать появляться и после исправления на сервере. Храните метку версии в имени кеша, размещайте изменяющееся содержимое под новым именем и позволяйте правилу активации удалять предыдущее.

Не используйте worker, чтобы перехватывать, переписывать или сохранять данные сверх того, что нужно странице для работы. Цель этого жизненного цикла состоит в меньшем и более предсказуемом хранилище, а не в скрытом слое, удерживающем ответы, которых никто не видит. Сохраняйте очистку видимой для людей, которые эксплуатируют сайт.

Держите код очистки небольшим и проверенным. Процедура, которая перечисляет имена, фильтрует их по префиксу и удаляет старые версии, достаточно коротка, чтобы прочитать её на проверке. Запускайте её в контексте, где уже накопилось несколько старых версий, ведь процедура, проверенная только на чистой установке, никогда не встречает случай, ради которого создана. Во время тестирования выводите имена удаляемых кешей в консоль разработчика, чтобы потом сравнить результат со списком кешей.

Выход из аккаунта, смена аккаунта и Clear-Site-Data

Некоторые ответы относятся к конкретному вошедшему пользователю. Кеш, который их хранит, нельзя считать безобидным офлайн-ресурсом: после выхода или смены аккаунта на общем устройстве следующий пользователь может увидеть то, что сохранил предыдущий аккаунт. Лучше не кешировать аутентифицированные или привязанные к аккаунту ответы. Если функции они нужны офлайн, ограничьте кеш этим аккаунтом и удаляйте его по окончании сессии.

Порядок шагов при выходе имеет значение. Сначала завершите серверный сеанс, затем удалите кеши аккаунта, затем очистите состояние, которое страница хранит в памяти. Если у приложения открыто несколько вкладок, сообщите остальным вкладкам, что аккаунт изменился, например широковещательным сообщением, чтобы оставшаяся открытой вкладка не продолжала показывать кешированные данные предыдущего аккаунта. Проверяйте последовательность при двух открытых вкладках, потому что проверка с одной вкладкой скрывает этот случай.

При выходе приложение может удалить кеши аккаунта кодом страницы и сообщить worker, что нужно сбросить состояние в памяти. Спецификация Clear-Site-Data также определяет заголовок ответа, директивы которого могут попросить браузер очистить кешированные или сохранённые данные источника, а директива хранилища охватывает доступное скриптам хранилище источника и отменяет регистрацию его сервис-воркеров; спецификация не называет CacheStorage по имени. Поддержка директив и точный охват различаются между браузерами, поэтому подтверждайте результат в каждом браузере, которым пользуются ваши пользователи, а не полагайтесь на название заголовка.

Заголовки сервера помогают, но не заменяют логику worker. Ответ, помеченный как не подлежащий сохранению, сообщает общим и приватным кешам, как себя вести, однако CacheStorage оставляет это решение коду worker, который сам выбирает, помещать ли ответ в кеш. Пусть worker проверяет, что собирается сохранить, и по умолчанию держите ответы, привязанные к аккаунту, вне долгоживущих кешей. Короткий явный список путей, которые можно кешировать, проще проверить, чем длинный список исключений.

Смена аккаунта заслуживает такого же внимания, как и выход, потому что профиль браузера остаётся тем же, а пользователь меняется. Очистите или ограничьте кеши первого аккаунта до загрузки второго, а затем прочитайте список кешей и убедитесь в этом. Чтение списка надёжнее, чем уверенность в том, что код очистки выполнился.

Людям, которые пользуются общим устройством, нужен понятный способ стереть сохранённые данные. Если приложение хранит данные аккаунта офлайн, предложите при выходе или в настройках чёткий элемент управления, который их удаляет, и простыми словами скажите, что будет удалено. Пользователи общих устройств не могут сами просмотреть CacheStorage, поэтому приложение остаётся единственным местом, где можно предложить такой выбор.

Держите эту границу понятной и для пользователей. Видимый выход, который незаметно оставляет ответы аккаунта на устройстве, считается дефектом приватности, даже если никакой трекер не участвует. Дополнительный контекст о том, как браузеры разделяют состояние, есть в материалах о разделении хранилища и приватности и об управлении cookie.

Проверка поведения кеша по контекстам

BotBrowser позволяет назначить каждому BrowserContext собственное хранилище и состояние сессии, а сервис-воркеры, созданные в контексте, наследуют отпечаток этого контекста, поэтому команда может проверять жизненный цикл кеша worker отдельно для каждой идентичности. BotBrowser не пишет, не версионирует и не очищает кеши сервис-воркера приложения и не может сделать безопасным дизайн с устаревшим или протекающим кешем; именование кешей, очистка при активации и очистка при выходе остаются ответственностью приложения.

Изоляция по контекстам полезна тем, что один и тот же сайт можно загрузить в двух контекстах с разными аккаунтами, и каждый контекст покажет собственную регистрацию и собственный список кешей. Если второй контекст показывает записи, созданные первым, у приложения проблема с областью действия, а не проблема браузера. Документация по мультиаккаунтной изоляции описывает модель хранилища по контекстам, а изоляция браузера для нескольких аккаунтов объясняет, как команды её планируют.

Практическая проверка использует два контекста. В первом контексте войдите под одним аккаунтом, загрузите приложение, дайте worker установиться и откройте несколько страниц. Запишите состояние регистрации и имена кешей. Во втором контексте войдите под другим аккаунтом и запишите те же сведения. В двух списках не должно быть общих записей, привязанных к аккаунту. Затем выйдите из аккаунта в первом контексте и снова прочитайте его список кешей. Наконец, убедитесь, что во втором контексте остались его собственные записи, то есть очистка в одном контексте не затронула другой.

Держите запись небольшой и воспроизводимой. Отметьте версию браузера, имя контекста, версию скрипта worker, список кешей до и после обновления, список кешей после выхода и состояние worker. Не вставляйте в запись тела ответов, токены и данные клиентов. Короткого списка имён кешей с результатами «пройдено» или «не пройдено» достаточно для проверки релиза, и он позволяет следующему человеку повторить ту же проверку после очередного развёртывания.

Проводите такую же проверку жизненного цикла в каждом контексте, важном для продукта, и записывайте результат отдельно по контексту. Не переносите успешный результат одного контекста на другой.

Выполните проверки жизненного цикла кеша

Выполните эти проверки в инструментах разработчика браузера или коротким скриптом и запишите «пройдено» или «не пройдено» для каждого кеша.

  1. Назовите этапы жизненного цикла, которые использует worker (регистрация, установка, ожидание, активация, fetch). Пройдено, если версионированные кеши создаются в обработчике установки и удаляются в обработчике активации. Не пройдено, если очистка выполняется при установке.
  2. Перечислите имена кешей, их метки версий и владельцев. Пройдено, если каждое имя соответствует одной версии worker и одной категории данных. Не пройдено для любого имени, которое никто не может объяснить.
  3. Запишите правило очистки при активации и правило для выхода из аккаунта. Пройдено, если в обоих указано, что сохраняется и что удаляется.
  4. После активации нового worker снова выведите список кешей. Пройдено, если не осталось кеша старой версии. Не пройдено, если старое имя всё ещё присутствует. Пока worker ожидает, отметьте старый кеш как отложенный.
  5. Проверьте состояние worker после обновления. Пройдено, если новый worker активен или отмечен как ожидающий. Не пройдено, если проверяющий счёл его работающим, не прочитав состояние.
  6. Найдите кеши, в которых лежат аутентифицированные ответы или ответы, привязанные к аккаунту. Пройдено, если они ограничены аккаунтом и исчезают после выхода или смены аккаунта. Не пройдено, если с ними обращаются как с обычными офлайн-ресурсами.
  7. Повторите проверки с 1 по 6 в каждом контексте браузера и запишите отдельный результат для каждого.

Источники

#Сервис-Воркеры#Кеширование#Конфиденциальность Браузера#Контексты Браузера

Переведите BotBrowser из исследований в продакшн

Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.