Spec-Zone.ru › Playwright

Сервис-воркеры

Введение​

предупреждение

Сервис-воркеры поддерживаются только в браузерах на базе Chromium.

примечание

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

Сервис-воркеры предоставляют встроенный в браузер способ обработки запросов, выполняемых страницей с помощью встроенного Fetch API (fetch), а также других сетевых ресурсов (например, скриптов, CSS и изображений).

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

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

Как отключить сервис-воркеры​

Playwright позволяет отключать сервис-воркеры во время тестирования. Это делает тесты более предсказуемыми и быстрыми. Однако поведение может отличаться, если на вашей странице используется сервис-воркер.

Чтобы отключить сервис-воркеры, задайте для testOptions.serviceWorkers значение 'block'.

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    serviceWorkers: 'allow'
  },
});

Доступ к сервис-воркерам и ожидание активации​

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

const serviceWorkerPromise = context.waitForEvent('serviceworker');
await page.goto('/example-with-a-service-worker.html');
const serviceworker = await serviceWorkerPromise;

Событие browserContext.on('serviceworker') срабатывает до того, как сервис-воркер возьмет страницу под управление. Поэтому перед выполнением кода в воркере с помощью worker.evaluate() необходимо дождаться его активации.

Есть более идиоматичные способы дождаться активации сервис-воркера, но следующий способ не зависит от реализации:

await page.evaluate(async () => {
  const registration = await window.navigator.serviceWorker.getRegistration();
  if (registration.active?.state === 'activated')
    return;
  await new Promise(resolve => {
    window.navigator.serviceWorker.addEventListener('controllerchange', resolve);
  });
});

Сетевые события и маршрутизация​

Все сетевые запросы, выполняемые сервис-воркером, регистрируются объектом BrowserContext:

  • Срабатывают события browserContext.on('request'), browserContext.on('requestfinished'), browserContext.on('response') и browserContext.on('requestfailed')
  • browserContext.route() перехватывает запрос
  • request.serviceWorker() будет содержать экземпляр сервис-воркера, а вызов request.frame() выбросит исключение

Кроме того, для любого сетевого запроса, выполненного страницей, метод response.fromServiceWorker() возвращает true, если запрос был обработан обработчиком fetch сервис-воркера.

Рассмотрим простой сервис-воркер, который выполняет fetch для каждого запроса страницы:

self.addEventListener('fetch', event => {
  // actually make the request
  const responsePromise = fetch(event.request);
  // send it back to the page
  event.respondWith(responsePromise);
});

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
});

Если index.html зарегистрирует этот сервис-воркер, а затем выполнит fetch для data.json, будут сгенерированы следующие события Request/Response (вместе с соответствующими событиями сетевого цикла):

Событие Владелец URL Маршрутизирован response.fromServiceWorker()
browserContext.on('request') Фрейм index.html Да
page.on('request') Фрейм index.html Да
browserContext.on('request') Сервис-воркер transparent-service-worker.js Да
browserContext.on('request') Сервис-воркер data.json Да
browserContext.on('request') Фрейм data.json Да
page.on('request') Фрейм data.json Да

В этом примере сервис-воркер работает лишь как простой прозрачный «прокси»:

  • Для data.json срабатывают 2 события browserContext.on('request'): одно принадлежит фрейму, другое — сервис-воркеру.
  • Через browserContext.route() можно маршрутизировать только запрос ресурса, принадлежащий сервис-воркеру. События, принадлежащие фрейму и относящиеся к data.json, маршрутизировать нельзя: они в принципе не могли обратиться к внешней сети, поскольку у сервис-воркера зарегистрирован обработчик fetch.
внимание

Важно: вызов request.frame() или response.frame() выбросит исключение, если он выполнен для запроса/ответа, у которого request.serviceWorker() возвращает ненулевое значение.

Маршрутизация только запросов сервис-воркера​

await context.route('**', async route => {
  if (route.request().serviceWorker()) {
    // NB: calling route.request().frame() here would THROW
    await route.fulfill({
      contentType: 'text/plain',
      status: 200,
      body: 'from sw',
    });
  } else {
    await route.continue();
  }
});

Известные ограничения​

Запросы на обновление кода основного скрипта сервис-воркера в настоящее время нельзя маршрутизировать (https://github.com/microsoft/playwright/issues/14711).

© 2026 Microsoft
Licensed under the Apache License, Version 2.0.
https://playwright.dev/docs/service-workers

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API