Гид по технологиям

Веб Push: полное руководство по реализации уведомлений в браузере

10 min read Frontend Обновлено 01 Dec 2025
Веб Push: полное руководство по уведомлениям
Веб Push: полное руководство по уведомлениям

Фото смартфона с иконками уведомлений, визуализированными, словно вылетающими из экрана

Быстрые ссылки

  • Сервис-воркер
  • Регистрация подписки на push
  • Когда запрашивать подписку у пользователя
  • Обработка истечений и обновлений подписок
  • Добавление кнопок действий в уведомления
  • Чек-лист внедрения
  • План отладки и отката
  • Резюме

Введение

Push-уведомления стали стандартной возможностью современных веб-приложений и PWA. Они дают способ донести важную информацию пользователю независимо от того, открыт ли сайт сейчас. Браузер получает push-событие и вызывает сервис-воркер, который затем отображает уведомление через интерфейсы ОС (центр уведомлений Windows, экран блокировки Android и т.п.).

Реализация Web Push на сайте требует работы с двумя отдельными компонентами:

  • Клиентская часть в сервис-воркере — она принимает push-события и отображает уведомления с помощью Notification API.
  • Серверная часть — она хранит подписки (endpoints и ключи) и отправляет зашифрованные push-сообщения через платформу доставки браузера.

Ниже — подробное, практическое руководство с примерами, проверками приёмки и планом на случай ошибок.

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

Сервис-воркер — это фоновый скрипт в браузере. Он реагирует на события: fetch, sync, push и другие. Для Web Push ключевое событие — push. Оно предоставляет объект PushEvent, через который доступен полезный нагруз (payload).

Пример минимальной обработки push в сервис-воркере:

self.addEventListener("push", e => {
  const payload = e.data ? JSON.parse(e.data.text()) : {title: "", body: ""};

  e.waitUntil(
    self.registration.showNotification(
      payload.title,
      {
        body: payload.body,
        icon: "/icon.png"
      }
    )
  );
});

Ключевые моменты:

  • showNotification() вызывается на self.registration.
  • Обёртка в e.waitUntil() гарантирует, что браузер не завершит работу воркера до отображения уведомления.
  • Сервер обычно отправляет JSON в поле данных push-сообщения. Код должен корректно обрабатывать отсутствие данных.

Дополнительно — регистрация сервис-воркера на стороне главного скрипта:

if (navigator.serviceWorker) {
  // Замените путь на ваш файл сервис-воркера
  navigator.serviceWorker.register('/sw.js').catch(() => {
    console.error("Не удалось зарегистрировать сервис-воркер.");
  });
}

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

Регистрация подписки на push

Подписку на push выполняют в основном коде приложения (не в сервис-воркере). Процесс выглядит так:

  1. Получить регистрацию сервис-воркера.
  2. Проверить наличие текущей подписки через pushManager.getSubscription().
  3. Если подписки нет — запросить публичный VAPID-ключ с сервера и вызвать pushManager.subscribe({applicationServerKey, userVisibleOnly: true}).
  4. Отправить данные подписки на сервер, связав их с пользователем/устройством.

Пример функции подписки:

async function subscribeToPush() {
  if (!navigator.serviceWorker) return;

  const reg = await navigator.serviceWorker.getRegistration();
  if (!reg || !reg.pushManager) return;

  const subscription = await reg.pushManager.getSubscription();
  if (!subscription) {
    const key = await fetch('https://example.com/vapid_key');
    const keyData = await key.text();

    const sub = await reg.pushManager.subscribe({
      applicationServerKey: keyData,
      userVisibleOnly: true
    });

    await fetch('https://example.com/push_subscribe', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        endpoint: sub.endpoint,
        expirationTime: sub.expirationTime,
        keys: sub.toJSON().keys
      })
    });
  }
}

// вызов
await subscribeToPush();

Пояснения:

  • applicationServerKey — это публичный ключ VAPID (URL-safe base64) в формате, который принимает браузер.
  • userVisibleOnly: true указывает браузеру, что все push-сообщения будут отображать уведомление пользователю.
  • PushSubscription.toJSON() возвращает keys с полями p256dh и auth, которые нужны серверу для шифрования и подписи.

Пример серверного потока отправки уведомлений

На сервере последовательность обычно такова:

  1. Получить подписки (endpoints + keys) для пользователя/группы.
  2. Сформировать и подписать VAPID-заголовки.
  3. Отправить зашифрованный payload на endpoint каждой подписки (через fetch или HTTP-клиент).
  4. Обработать ошибки (410 Gone — обычно значит, что подписка удалена) и удалить такие записи из БД.

Не используйте необработанные ответы от доставщика уведомлений: всегда логируйте коды ошибок и корректно удаляйте устаревшие endpoints.

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

Запрос разрешения на отправку уведомлений вызывает браузерное диалоговое окно. Моменты, когда стоит предлагать подписку:

  • После прямого пользовательского действия: клик по кнопке “Включить уведомления”.
  • После объяснения ценности через баннер или модальное окно: опишите, что именно пользователь получит.
  • Не показывайте системный диалог сразу на входе — часто это приведёт к отказу.

Пример UX-баннера: сначала показывайте кастомный баннер с кнопкой “Включить уведомления”. При клике вызывайте подписку.

Скриншот баннера с предложением включить push-уведомления

Обязательно предоставьте в приложении возможность отписаться. Пользователь может отозвать разрешение через настройки браузера, но удобная внутренняя кнопка для отписки улучшит доверие.

Пример отписки:

async function unsubscribePush() {
  const reg = await navigator.serviceWorker.getRegistration();
  const subscription = await reg.pushManager.getSubscription();
  if (subscription) {
    await subscription.unsubscribe();
    await fetch(`https://example.com/push_unsubscribe/${encodeURIComponent(subscription.endpoint)}`, {method: 'DELETE'});
  } else {
    // уже отписан
  }
}

Обработка истечения и обновлений подписки

Объект PushSubscription может содержать поле expirationTime. На практике современные браузеры часто оставляют это поле null. Тем не менее, подписки могут меняться из-за обновлений платформы доставки.

Событие pushsubscriptionchange позволяет реагировать на изменение подписки. Есть две версии события: v1 (старое поведение) и v2 (новое). В старом варианте браузер удаляет подписку и не даёт прямого доступа к старому endpoint. В v2 событие содержит oldSubscription и newSubscription, что упрощает обновление серверной записи.

Рекомендуется реализовать обработчик для нового API и также иметь запасной механизм, если браузер поддерживает только старую версию — например, хранить текущий endpoint в IndexedDB или localStorage.

Пример реализации для v2:

self.addEventListener('pushsubscriptionchange', e => {
  e.waitUntil((async () => {
    // e.newSubscription и e.oldSubscription могут быть null в зависимости от реализации
    if (e.newSubscription) {
      await fetch('https://example.com/push_change', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          auth: (e.newSubscription.toJSON().keys?.auth || null),
          endpoint: e.newSubscription.endpoint,
          endpointOld: e.oldSubscription ? e.oldSubscription.endpoint : null,
          expirationTime: e.newSubscription.expirationTime,
          p256dh: (e.newSubscription.toJSON().keys?.p256dh || null)
        })
      });
    } else {
      // fallback: попробовать заново подписаться или уведомить сервер, что подписка пропала
    }
  })());
});

Если хотите поддержать старое поведение, отслеживайте endpoint в IndexedDB и используйте его внутри обработчика, чтобы отправить серверу старый URL.

Компоненты уведомления и кнопки действий

Notification API позволяет задавать заголовок, тело, иконку, бейдж, паттерн вибрации и кнопки действий (actions). Каждое действие получает поле action, которое может быть строкой или URI — оно передаётся в событии notificationclick.

Пример уведомления с кнопкой:

self.registration.showNotification(
  "Notification with actions",
  {
    body: "This notification has a button.",
    actions: [
      {
        action: "/home",
        title: "Go to Homescreen",
        icon: "/home.png"
      }
    ]
  }
);

Обработка клика по уведомлению и по кнопке:

self.addEventListener('notificationclick', e => {
  const action = e.action; // строка, которую вы указали в actions
  const notification = e.notification;
  notification.close();

  // Открыть окно или фокусировать уже открытый клиент
  e.waitUntil(clients.matchAll({type: 'window'}).then(windowClients => {
    for (let client of windowClients) {
      if (client.url === `${self.location.origin}${action}` && 'focus' in client) {
        return client.focus();
      }
    }
    if (clients.openWindow) {
      return clients.openWindow(`${self.location.origin}${action}`);
    }
  }));
});

Обратите внимание:

  • Всегда вызывайте notification.close() при обработке клика, чтобы уведомление не висело в UI.
  • На разных платформах действия могут выглядеть и работать по-разному. Тестируйте на целевых ОС.

Скриншот push-уведомления Microsoft Edge в Windows 10

Чек-лист внедрения (роль: разработчик фронтенда)

  • Зарегистрирован и корректно обновляется сервис-воркер.
  • Реализован обработчик push в сервис-воркере с e.waitUntil().
  • Реализован вызов showNotification() с полезной структурой payload.
  • Реализована подписка pushManager.subscribe() и отправка подписки на сервер.
  • На сервере хранятся endpoint, p256dh, auth и привязка к пользователю/устройству.
  • Обработаны ошибки отправки на сервере (410/404/403) и удаление устаревших подписок.
  • Реализована отписка на клиенте и удаление записи на сервере.
  • Добавлен UX для запроса разрешений (перед показом системного диалога показывать объясняющий баннер).
  • Тестирование на целевых браузерах и ОС (Chrome Desktop/Android, Firefox, Edge; Safari — частично поддерживает/не поддерживает в зависимости от версии).
  • Реализован pushsubscriptionchange и резервное хранение endpoint.
  • Включены механизмы логирования и мониторинга отправки push-сообщений.

План отладки, ошибки и откат

  1. Локальная проверка сервис-воркера: откройте DevTools -> Application -> Service Workers. Убедитесь, что sw.js зарегистрирован и нет ошибок.
  2. Проверка подписки: в консоли выполните navigator.serviceWorker.getRegistration().then(r=>r.pushManager.getSubscription()).then(console.log).
  3. Логи сервера: проверяйте ответы от поставщика push (статусы 201/200/410/404 и тела ошибок).
  4. Ошибки отправки: 410 Gone — удаляйте подписку; 403/401 — проверьте VAPID; 400 — проверьте формат и шифрование payload.
  5. Откат: если новая версия сервис-воркера вызывает регрессии, фиксируйте версию и возвращайте предыдущий sw.js в CDN/серверном релизе. Браузер обновит сервис-воркер при следующей перезагрузке.

Критические шаги при инциденте:

  • Отключить массовую отправку уведомлений, чтобы не посылать вредоносный или спам-контент.
  • Проанализировать логи доставщика уведомлений.
  • Уведомить команду поддержки и при необходимости пользователей (через email или сайт).

Безопасность и приватность

  • VAPID — это механизм аутентификации отправителя. Храните приватный ключ VAPID в защищённом месте (на сервере), не в клиентском коде.
  • Payload обычно шифруется с использованием ключей, переданных браузером (p256dh и auth). Используйте проверенные библиотеки для шифрования Web Push (например, web-push для Node.js).
  • Сохраняйте минимум пользовательских данных в подписке. Связывайте endpoint с внутренним идентификатором устройства/пользователя, а не с PII напрямую.
  • Подумайте о GDPR/локальной регуляции: явное согласие пользователя и возможность полного удаления подписки и связанных данных.

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

Совместимость и особенности разных браузеров

  • Chrome (Desktop/Android) — активно поддерживает Web Push, полностью реализует VAPID и шифрование.
  • Firefox — поддерживает Web Push; исторически использовал собственный механизм доставки, но API поддерживается.
  • Edge (Chromium) — поведение похоже на Chrome.
  • Safari — долгое время не поддерживал стандартный Web Push; новые версии Safari и iOS постепенно добавляют поддержку, но стоит проверять актуальность и особенности платформы.

Тестируйте на реальных устройствах и версиях ОС, так как внешний вид и поведение уведомлений (иконки, действия, приоритет) сильно зависят от системы.

Дополнительные подходы и альтернативы

  • Использовать сторонние сервисы (Firebase Cloud Messaging, OneSignal и т. п.) для упрощённого управления подписками и аналитики. Это снимает часть работы по шифрованию и VAPID, но добавляет внешнюю зависимость.
  • Для критичных уведомлений — реализовать дополнительную доставку через email или SMS как резервный канал.

Когда Web Push не подходит:

  • Если сообщение требует высокой безопасности и конфиденциальности, лучше использовать защищённые каналы внутри приложения, а не push.
  • Если большая часть пользовательской базы не согласится на разрешения, вложите усилия в улучшение UX предложения подписки или предложите альтернативные каналы.

Примеры тестовых сценариев и критерии приёмки

Критерии приёмки для релиза функционала Web Push:

  • Подписка: пользователь может подписаться и сервер получает endpoint + ключи.
  • Получение: подписанный пользователь получает уведомление при отправке тестового payload.
  • Отображение: текст уведомления и иконка отображаются корректно на целевых платформах.
  • Кнопки действий: нажатие на действие открывает ожидаемый URL или фокусирует окно приложения.
  • Отписка: пользователь может отписаться, и сервер прекращает отправку уведомлений этому endpoint.
  • Обработка 410: сервер удаляет устаревшие endpoints при получении статуса 410.

Тест-кейсы:

  • Подписать новый пользовательский агент и отправить уведомление с пустым payload.
  • Отправить уведомление с кнопками действий и проверить notificationclick.
  • Принудительно вызвать unsubscribe и проверить, что push событие больше не доставляется.
  • Смоделировать ответ поставщика 410 и убедиться, что запись удаляется на сервере.

Модели зрелости (Maturity levels)

  • Уровень 0 — без уведомлений.
  • Уровень 1 — базовая подписка и отправка уведомлений; нет удобного UX для подписки и отписки.
  • Уровень 2 — UX-баннеры, обработка ошибок на сервере, логирование доставок и ошибок.
  • Уровень 3 — аналитика доставок и открытий, сегментация подписок, A/B-тесты для сообщений.
  • Уровень 4 — персонализация, динамическое формирование payload, резервные каналы доставки.

Планируйте эволюцию от базовой реализации к более зрелым уровням по приоритету для бизнеса.

Решающее дерево для принятия решения о включении Web Push (Mermaid)

flowchart TD
  A[Есть важные срочные сообщения?] -->|Да| B[Пользователи готовы принимать push?]
  A -->|Нет| C[Отложить push]
  B -->|Да| D[Внедряем Web Push]
  B -->|Не уверены| E[Добавить баннер, провести тест]
  E -->|Положительный результат| D
  E -->|Отрицательный| C

Типовые ошибки и как их исправить

  • Ошибка: pushManager отсутствует. Причина: сервис-воркер не зарегистрирован или браузер не поддерживает Web Push. Проверка: navigator.serviceWorker и Service Worker registration.
  • Ошибка: 403 при отправке push с сервера. Причина: неправильные VAPID-ключи или плохая подпись. Решение: проверьте приватный ключ VAPID и библиотеку отправки.
  • Ошибка: уведомления приходят, но без данных. Причина: сервер не прикрепил payload или браузер-бэкэнд удалил payload из-за ограничений. Решение: убедитесь, что вы отправляете зашифрованный payload корректно и обрабатываете null e.data на стороне воркера.
  • Ошибка: notificationclick не срабатывает на некоторых платформах. Причина: отличия в реализации. Решение: тестируйте на целевых устройствах и реализуйте fallback (например, открывать страницу при клике на тело уведомления).

Шаблон политики уведомлений для продукта (короткая версия)

  • Типы уведомлений: критические, информационные, маркетинговые.
  • Критические уведомления отправлять всем подписанным пользователям; маркетинговые — только тем, кто явно согласился.
  • Частота: не более N маркетинговых уведомлений в неделю (зависит от продукта).
  • Уникальность контента: избегать дублирования и спама.
  • Приватность: не включать PII в payload.

Короткое руководство для команды поддержки

  • Проверить, подписан ли пользователь: попросить его открыть сайт, открыть DevTools или отправить снимок экрана блокировки/центра уведомлений.
  • Если пользователь не получает уведомления: проверить, не отключены ли уведомления в настройках ОС/браузера.
  • Для массовых проблем: проверить статус отправщика push (утечки ключей, изменение VAPID).

1-строчная глоссарий

  • Service Worker — фоновой JavaScript-скрипт, реагирующий на события.
  • Push API / PushManager — API для управления подписками на push.
  • PushSubscription — объект, описывающий подписку (endpoint + ключи).
  • VAPID — способ аутентификации отправителя уведомлений.

Резюме

Web Push — мощный инструмент для связи с пользователями. Его внедрение требует синхронной работы клиентской логики (сервис-воркер, Notification API) и серверной части (хранение подписок, VAPID, шифрование payload). Фокусируйтесь не только на технической реализации, но и на UX: объясняйте пользователю ценность уведомлений, давайте простой путь для отписки и соблюдайте правила приватности.

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

Скриншот push-уведомления Microsoft Edge в Windows 10 с кнопкой действия

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

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Spotify не может воспроизвести трек — способы исправить
Руководство

Spotify не может воспроизвести трек — способы исправить

Установка Google Play на Windows 11
Руководство

Установка Google Play на Windows 11

AirDrop на Apple: настройка и безопасность
How-to

AirDrop на Apple: настройка и безопасность

Уведомления об истечении пароля в Active Directory
Security

Уведомления об истечении пароля в Active Directory

Задержка в Routines Google Assistant
Гайды

Задержка в Routines Google Assistant

Вход по отпечатку пальца в Ubuntu
Безопасность

Вход по отпечатку пальца в Ubuntu