Back

Реализация Push-уведомлений с помощью Web Push API

Реализация Push-уведомлений с помощью Web Push API

Push-уведомления поддерживают вовлечённость пользователей даже когда они не используют ваше веб-приложение активно. Web Push API позволяет отправлять своевременные обновления напрямую на устройства пользователей без использования сторонних сервисов. Это руководство показывает, как реализовать нативные уведомления с использованием Service Workers, VAPID-аутентификации и правильного шифрования.

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

  • Web Push API обеспечивает нативные push-уведомления без сторонних сервисов
  • Service Workers и VAPID-аутентификация являются основными компонентами
  • HTTPS-соединение обязательно для реализации
  • Разные браузеры имеют различные требования к push-уведомлениям

Предварительные требования и поддержка браузерами

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

  • HTTPS-соединение (обязательно для Service Workers)
  • Поддержка современных браузеров (Chrome, Firefox, Edge, Safari 16.4+)
  • Совместимость с Service Worker
// Feature detection
if ('serviceWorker' in navigator && 'PushManager' in window) {
  // Push notifications supported
}

Регистрация Service Worker

Service Worker выступает в качестве прокси между вашим веб-приложением и push-сервисами. Зарегистрируйте его при загрузке страницы:

navigator.serviceWorker.register('/sw.js')
  .then(registration => {
    console.log('Service Worker registered:', registration);
  })
  .catch(error => {
    console.error('Registration failed:', error);
  });

Настройка VAPID-ключей

VAPID (Voluntary Application Server Identification) аутентифицирует ваш сервер в push-сервисах. Сгенерируйте пару ключей один раз для вашего приложения:

# Using web-push library (Node.js)
npm install web-push
npx web-push generate-vapid-keys

Храните приватный ключ в безопасности на вашем сервере и используйте публичный ключ в клиентской подписке.

Создание Push-подписок

Запросите разрешение и подпишите пользователей на push-уведомления:

async function subscribeToPush() {
  const registration = await navigator.serviceWorker.ready;
  
  // Request permission (only on user gesture)
  const permission = await Notification.requestPermission();
  if (permission !== 'granted') return;
  
  // Subscribe with VAPID public key
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
  });
  
  // Send subscription to your server
  await fetch('/api/subscribe', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(subscription)
  });
}

// Helper function to convert base64 to Uint8Array
function urlBase64ToUint8Array(base64String) {
  const padding = '='.repeat((4 - base64String.length % 4) % 4);
  const base64 = (base64String + padding)
    .replace(/\-/g, '+')
    .replace(/_/g, '/');
  
  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  
  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

Объект подписки содержит:

  • Endpoint: Уникальный URL для отправки сообщений
  • Keys: Ключи шифрования (p256dh и auth) для безопасности полезной нагрузки

Серверная реализация

Ваш сервер должен шифровать сообщения и отправлять их на endpoint push-сервиса. Использование библиотеки web-push упрощает это:

const webpush = require('web-push');

webpush.setVapidDetails(
  'mailto:your-email@example.com',
  VAPID_PUBLIC_KEY,
  VAPID_PRIVATE_KEY
);

// Send notification
const payload = JSON.stringify({
  title: 'New Message',
  body: 'You have a new update',
  icon: '/icon-192.png',
  url: 'https://example.com/updates'
});

webpush.sendNotification(subscription, payload, {
  TTL: 86400, // 24 hours
  urgency: 'high'
})
  .catch(error => {
    console.error('Error sending notification:', error);
  });

Обработка Push-событий в Service Worker

Service Worker получает и отображает push-уведомления:

// sw.js
self.addEventListener('push', event => {
  const data = event.data?.json() || {};
  
  const options = {
    body: data.body || 'Default message',
    icon: data.icon || '/icon.png',
    badge: '/badge.png',
    vibrate: [200, 100, 200],
    data: { url: data.url }
  };
  
  event.waitUntil(
    self.registration.showNotification(data.title || 'Notification', options)
  );
});

// Handle notification clicks
self.addEventListener('notificationclick', event => {
  event.notification.close();
  
  event.waitUntil(
    clients.openWindow(event.notification.data?.url || '/')
  );
});

Требования для конкретных браузеров

Различные браузеры применяют разные требования для реализации Web Push API:

  • Chrome/Edge: Требуют видимые уведомления для каждого push-сообщения
  • Firefox: Позволяет ограниченные тихие push с системой квот
  • Safari: Требует видимые уведомления и не поддерживает тихие push

Примечание: Размеры полезной нагрузки ограничены: Chrome/Edge/Firefox поддерживают до 4 КБ, в то время как Safari поддерживает 2 КБ. Сохраняйте сообщения лёгкими и загружайте дополнительные данные в приложении при необходимости.

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

Рекомендации по безопасности

Защитите вашу реализацию push-уведомлений:

  1. Защищённые endpoints: Никогда не раскрывайте endpoints подписки публично
  2. Шифруйте полезную нагрузку: Все данные сообщений должны использовать ECDH-шифрование
  3. Защищайте VAPID-ключи: Храните их в безопасности и перегенерируйте только в случае компрометации
  4. Реализуйте CSRF-защиту: Валидируйте запросы на подписку
  5. Ограничение частоты запросов: Предотвращайте злоупотребления с помощью серверного троттлинга

Управление жизненным циклом подписки

Обрабатывайте изменения и истечение подписки:

// In Service Worker
self.addEventListener('pushsubscriptionchange', event => {
  event.waitUntil(
    self.registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
    })
      .then(subscription => {
        // Update server with new subscription
        return fetch('/api/update-subscription', {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(subscription)
        });
      })
  );
});

Заключение

Web Push API предоставляет стандартизированный подход к реализации push-уведомлений без привязки к конкретному поставщику. Комбинируя Service Workers, VAPID-аутентификацию и правильное шифрование, вы можете доставлять своевременные уведомления, которые работают в современных браузерах. Не забывайте уважать предпочтения пользователей, обрабатывать события жизненного цикла подписки и следовать платформенным требованиям для надёжной реализации.

Начните с базовой доставки уведомлений, затем добавляйте функции, такие как кнопки действий, вложения изображений и группировка уведомлений по мере развития вашей реализации.

Часто задаваемые вопросы

Нет, push-уведомления требуют активного подключения к интернету для получения сообщений от push-сервиса. Однако Service Workers могут кэшировать уведомления и отображать их при восстановлении соединения.

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

Большинство push-сервисов ограничивают размер полезной нагрузки до 4 КБ. Chrome и Firefox поддерживают до 4 КБ, в то время как Safari поддерживает до 2 КБ. Сохраняйте полезную нагрузку минимальной и загружайте дополнительные данные при получении уведомления при необходимости.

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

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay