Push-уведомления широко используются как в браузерах, так и в мобильных приложениях. У вас нет шанса не столкнуться с ними как с пользователем. Цель этой статьи - предоставить шаблон для веб-push-уведомлений с использованием распространенных технологий: Node.js и Express на бэкэнде и React.js (Create React App) во фронтенде.

Во-первых, давайте опишем обобщенный жизненный цикл веб-push-уведомлений:

  1. Клиентское приложение устанавливает сервисного работника. Это автономно работающий скрипт в вашем браузере, который в последние годы выполняет все больше и больше функций. Таким образом, даже если вкладка с приложением в данный момент не открыта, работник службы примет и покажет уведомление.
  2. Пользователь получает запрос на отображение уведомлений.
  3. После получения разрешения на отображение уведомлений браузер передает приложению учетные данные и другую служебную информацию. Эти данные должны быть отправлены на серверную часть и сохранены в базе данных.
  4. Используя ранее полученные учетные данные, серверная часть делает запрос поставщику услуг, который, в свою очередь, отправляет уведомление работнику службы.
  5. Сервисный работник получает уведомление и показывает его.

Теперь реализуем все необходимые компоненты. Вы можете воспроизвести шаги, описанные ниже, или использовать готовый шаблон, ссылки на который приведены в конце статьи.

Шаг 1: Запуск приложения Node.js и получение ключей VAPID.

Инициализируем наше бэкэнд-приложение со всеми необходимыми зависимостями командой:
yarn add express dotenv body-parser cors web-push
Для защиты канала передачи уведомлений от постороннего вмешательства используются так называемые ключи VAPID. Открытый ключ отправляется в службу push-уведомлений во время подписки. В будущем ваше серверное приложение будет использовать эти ключи в качестве меры аутентификации при отправке уведомления через службу push. Вы можете сгенерировать ключи VAPID с помощью команды:
./node_modules/.bin/web-push generate-vapid-keys
N Теперь, когда у нас есть пара ключей, мы перейдем к созданию клиентского приложения и пройдем весь сценарий: от подписки до отправки уведомления.

Шаг 2: Создание приложения React и рабочего сервиса.

В качестве фронтенда мы будем использовать приложение React, а именно CRA. Это довольно популярный способ создания одностраничных приложений, поэтому в качестве иллюстрации я предпочел его обычному JS. С другой стороны, у CRA есть некоторые подводные камни с точки зрения использования сервис-воркера, которые будут рассмотрены ниже.

Итак, мы инициализируем наше приложение в новой папке web-push-front с помощью команды:
yarn create react-app web-push-front
Вы можете проверить работу приложения, выполнив команду yarn start и посетив http: // localhost: 3000 /

По умолчанию CRA работает таким образом, что служебный воркер отсутствует в режиме разработки, а любой ранее установленный служебный воркер заменяется фиктивным.
Для начала замените в src / index.js строка serviceWorker.unregister(); by serviceWorker.register();.

Затем мы модифицируем функцию register() в файле src / serviceWorker.js, удаляя условие:
process.env.NODE_ENV === 'production'
чтобы сервис воркер загружался не только в прод-режиме.

По умолчанию фиктивный файл, созданный на лету, передается в режим разработки по адресу http: // localhost: 3000 / service-worker.js. Чтобы обойти это, измените имя файла, заданного в режиме разработки, на custom-sw.js.

const swFileName = process.env.NODE_ENV === 'production' 
  ? 'service-worker.js' 
  : 'custom-sw.js'
const swUrl = `${process.env.PUBLIC_URL}/${swFileName}`;

Теперь давайте создадим сервис-воркера в общедоступной папке, который будет прослушивать событие push и отображать уведомления.

Теперь откройте DevTools с включенной опцией Обновлять при перезагрузке или ее эквивалентом в своем любимом браузере и перезагрузите страницу. В результате должен быть установлен custom-sw.js.
Вы можете проверить его работу, отправив тестовое локальное уведомление с таким содержанием:
{“body”: “devbody”, “title”: “devtest”}

Шаг 3. Подпишитесь на уведомления.

Сначала мы создаем файл .env, в который вводим URL-адрес нашей серверной части и ранее сгенерированный открытый ключ VAPID.

Теперь реализуйте весь скрипт подписки на уведомления в файле src / subscription.js.

Разберем подробнее. Основная функция subscribeUser () предназначена для обработки максимально возможных ситуаций: отсутствие поддержки push-уведомлений браузером, запрет отображения уведомлений пользователем и т. Д. Сама подписка создается путем вызова registration.pushManager.subscribe (), куда мы передаем наш публичный ключ VAPID. Прежде чем его нужно будет преобразовать, воспользуемся реализацией функции urlBase64ToUint8Array () из Учебника Google. В случае успешной подписки или при наличии существующей подписки мы получаем учетные данные. Каждый браузер реализует доставку push-уведомлений через свой сервис. На примере Google Chrome полученные учетные данные будут выглядеть так:

{
  endpoint: 'https://fcm.googleapis.com/fcm/send/chhjHsBv3DU:APA91bGJCZnXCfkGeAa2nlo5n3fkP4aNw1J7Y34s9neghg0KowAKJcUqIbm97TuuASOD8VD4CpWNpVrKaX3E1f-rwLaINlKOCwGUFCUtZG9qpYNBT3edlEF0mznLK3gJN3rp7XwJAc2y',
  expirationTime: null,
  keys: {
    p256dh: 'BBe1YEEq3YuUwYxekAYug5xdjTg18IUkvdTLjRjshN4lnbytK-b7_3iAbYEpgjsFRvboIPsc3h_3wWM8TCRisSc',
    auth: 'uQq5Eyjzvwv66ddqwXa1PA'
  }
}

После этого отправьте этот объект на серверную часть с помощью обычного запроса POST с вызовом sendSubscription ().
Наконец, импортируйте функцию subscribeUser () из подписки .js в index.js и добавьте его вызов в самый конец файла.

Шаг 4: Получение учетных данных на стороне сервера и отправка уведомления.

Пришло время вдохнуть жизнь в шаблон Node-приложения.
Для начала мы создаем файл .env, в котором указываем пару ключей VAPID, а также ваш контактный адрес отправителя уведомлений.

Затем для простоты реализуем всю логику серверного приложения в одном файле index.js.

Что там происходит:

  1. Инициализируйте платформу Express.
  2. Используйте env-config.
  3. Отключите политику безопасности CORS. Будьте осторожны и сознательно настраивайте это на производстве.
  4. Применяем body-parser.
  5. Модуль веб-push инициализируется ключами VAPID и контактным адресом.
  6. Тестовая конечная точка GET, чтобы убедиться, что сервер работает.
  7. Конечная точка, принимающая запрос с учетными данными. В реальном приложении они должны быть сохранены в базе данных. В нашем примере мы используем их для немедленной отправки уведомления.

Итак, мы запускаем сервер с помощью команды node index.js и переходим на http: // localhost: 9000, чтобы убедиться, что он работает.
Теперь оба приложения готовы, и вы можете снова открыть клиентскую часть и увидеть всплывающее окно с запросом для разрешения уведомить. Если вы согласны, вы можете увидеть, как запрос с учетными данными отправляется на бэкэнд и после получения push-уведомления. Поздравляю!

Дополнительный шаг: подождите, а как насчет режима производства?

В этом случае Create React App компилирует файлы в папку build, и размещенный там служебный воркер по умолчанию содержит полезные для современных приложений вещи. Если мы решим сохранить их и просто добавить нашу push-функциональность, потребуется некоторая модификация процесса сборки. Для построения сервис-воркеров в CRA используется Workbox. И нет встроенного способа изменить его, даже если ваша цель - просто добавить какой-то собственный код. Считаю этот пакет наиболее удобным способом сделать это, если вы не готовы активно погружаться в исследования конфигурирования Workbox в контексте CRA.

Сначала добавьте новую зависимость:
yarn add cra-append-sw
После этого нам нужно расширить сценарий сборки в package.json, добавив туда новую команду, которая выполняется после основного процесса, чтобы что вся строка будет выглядеть так:
react-scripts build && cra-append-sw --skip-compile ./public/custom-sw.js

В результате содержимое custom-sw.js будет добавлено в самый конец файла build / service-worker.js.

И напоследок общие советы по стратегии отображения запроса на подписку. Если пользователь отклонит такой запрос, у вас не будет второго шанса предложить подписку, пока пользователь не отменит запрет в настройках браузера (а они вряд ли захотят это сделать). Так что используйте этот шанс с умом, выбрав подходящий момент: это точно не тот случай, когда пользователь попадает на ваш сайт впервые. Если вы хотите иметь возможность раздражать пользователя много раз, сначала покажите настраиваемый диалог с предложением о подписке. И только если пользователь согласен, покажите настоящий.

Если что-то пойдет не так, вы можете проверить шаблон:
Приложение узла: https://github.com/seladir/demo-webpush-node
Приложение React: https://github.com/seladir/demo-webpush-react