Subskrybowanie użytkownika

Najpierw musisz uzyskać od użytkownika zgodę na wysyłanie mu wiadomości push, wypróbuj PushSubscription.

Użycie interfejsu JavaScript API jest stosunkowo proste, więc nieprzekraczający ich logiki.

Wykrywanie cech

Najpierw musimy sprawdzić, czy bieżąca przeglądarka faktycznie obsługuje wiadomości push. Możemy sprawdzić, czy wypychanie jest obsługiwane na podstawie 2 prostych kontroli.

  1. Sprawdź zasób serviceWorker w narzędziu navigator.
  2. Sprawdź PushManager w oknie window.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

Liczba obsługiwanych przeglądarek jest coraz wyższa zarówno w przypadku mechanizmów Service Worker, w wiadomościach push, zawsze dobrze jest włączyć wykrywanie stopniowego ulepszania.

Rejestrowanie skryptu service worker

Dzięki funkcji wykrywania wiemy, że obsługiwane są zarówno mechanizmy Service Worker, jak i Push. Następny krok jest „rejestracja” nasz skrypt service worker.

Gdy rejestrujemy skrypt service worker, przeglądarka informuje przeglądarkę, gdzie znajduje się ten plik. Plik nadal to JavaScript, ale przeglądarka „udzieli do niego dostępu” do skryptu service worker Interfejsy API, w tym push. Dokładniej rzecz ujmując, przeglądarka uruchamia plik w skrypcie service worker dla środowiska.

Aby zarejestrować skrypt service worker, wywołaj navigator.serviceWorker.register(), przekazując ścieżkę do do pliku. W ten sposób:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

Ta funkcja informuje przeglądarkę, że mamy plik service worker i gdzie się znajduje. W w tym przypadku plik service worker znajduje się pod adresem /service-worker.js. Za kulisami przeglądarki po wywołaniu numeru register() wykona te czynności:

  1. Pobierz plik service worker.

  2. Uruchom kod JavaScript.

  3. Jeśli wszystko działa prawidłowo i nie ma błędów, obietnica zwrócona przez funkcję register() zostanie rozwiązany. Jeśli wystąpią jakiekolwiek błędy, obietnica zostanie odrzucona.

Jeśli register() odrzuci żądanie, dokładnie sprawdź kod JavaScript pod kątem literówek lub błędów w Narzędziach deweloperskich w Chrome.

Po rozwiązaniu problemu register() zwraca wartość ServiceWorkerRegistration. Wykorzystamy to aby uzyskać dostęp do interfejsu PushManager API.

Zgodność przeglądarki z interfejsem PushManager API

Obsługa przeglądarek

  • Chrome: 42.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

Źródło

Proszę o zgodę

Zarejestrowaliśmy nasz skrypt service worker i jest on gotowy do subskrypcji użytkownika. Następnym krokiem jest zgody użytkownika na wysyłanie mu wiadomości push.

Interfejs API do uzyskiwania uprawnień jest stosunkowo prosty. Wadą jest jednak to, interfejs API niedawno zmienił wywołanie zwrotne na zwrot obietnicy. Problem w tym, że nie możemy określić, która wersja interfejsu API jest zaimplementowana przeglądarki, więc musisz wdrożyć je wszystkie i je obsługiwać.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

W powyższym kodzie ważnym fragmentem kodu jest wywołanie funkcji Notification.requestPermission() Ta metoda spowoduje wyświetlenie użytkownikowi tych informacji:

Prośba o przyznanie uprawnień w Chrome na komputerach i urządzeniach mobilnych.

Gdy użytkownik wejdzie w interakcję z prośbą o uprawnienia, naciskając Zezwól, Blokuj lub zamykając wynik zostanie podany w postaci ciągu: 'granted', 'default' lub 'denied'.

W przykładowym kodzie powyżej obietnica zwrócona przez funkcję askPermission() jest rozpatrywana, jeśli uprawnienie zostanie zaakceptowana. W przeciwnym razie popełnimy błąd i odrzucimy obietnicę.

Jedną z skrajnych sytuacji jest kliknięcie przycisku „Zablokuj” Przycisk Jeśli aplikacja nie będzie mogła ponownie poprosić użytkownika o zgodę. Będą musieli ręcznie „odblokuj” przez zmianę stanu uprawnień aplikacji, która jest w kodzie w panelu ustawień. Dobrze zastanów się, w jaki sposób i kiedy prosisz użytkownika o zgodę, bo jeśli klikną przycisk blokowania, nie będzie można łatwo cofnąć tej decyzji.

Dobra wiadomość jest taka, że większość użytkowników chętnie udziela zgody wie, dlaczego prosi o pozwolenie.

Później omówimy, w jaki sposób niektóre popularne witryny proszą o zgodę.

Subskrybowanie użytkownika za pomocą PushManager

Gdy już zarejestrujemy mechanizm Service Worker i otrzymamy zgodę użytkownika, Dzwonię pod registration.pushManager.subscribe().

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

Wywołując metodę subscribe(), przekazujemy obiekt options, który składa się z obu wymagane i opcjonalne parametry.

Przyjrzyjmy się wszystkim opcjom, które można przekazać.

Opcje userVisibleOnly

Kiedy po raz pierwszy dodano tryb push do przeglądarek, nie było pewności, czy programiści powinni wysyłać wiadomości push bez wyświetlania powiadomień. Jest to tzw. tryb cichy ponieważ użytkownik nie wiedział, że coś wydarzyło się w tle.

Deweloperzy mogli się obawiać, że programiści mogli wykonywać szkodliwe działania, np. śledzić lokalizację użytkownika na bez wiedzy użytkownika.

Aby uniknąć takiej sytuacji i dać autorom specyfikacji czas na zastanowienie się, jak najlepiej temu zaradzić funkcja userVisibleOnly została dodana i przekazanie wartości true jest symbolem zgadza się z przeglądarką, że aplikacja internetowa będzie pokazywać powiadomienie przy każdym żądaniu push odebranie (tj. brak cichych powiadomień push).

W tej chwili musisz przekazać wartość true. Jeśli nie podasz parametru userVisibleOnly klucz lub przekaz w false spowoduje błąd:

Chrome obsługuje obecnie interfejs Push API tylko w przypadku subskrypcji, które powodują Możesz to poinformować, dzwoniąc pushManager.subscribe({userVisibleOnly: true}). Zobacz Więcej informacji znajdziesz na stronie https://goo.gl/yqv4Q4.

Obecnie wygląda na to, że dyskretne przekazywanie push nigdy nie zostanie wdrożone w Chrome. Zamiast tego: autorzy specyfikacji pracują nad koncepcją budżetowego interfejsu API, który pozwoli aplikacjom internetowym liczba cichych wiadomości push na podstawie użycia aplikacji internetowej.

Opcja applicationServerKey

Wspomnieliśmy krótko o „kluczach serwera aplikacji”. w poprzedniej sekcji. „Aplikacja klucze serwera” są używane przez usługę push do identyfikowania aplikacji subskrybującej użytkownika oraz upewnić się, że ta sama aplikacja wysyła wiadomości do tego użytkownika.

Klucze serwera aplikacji to para kluczy publicznych i prywatnych, które są unikalne dla Twojej aplikacji. Klucz prywatny powinien być tajny dla aplikacji, a klucz publiczny może być dostępny dla wszystkich. swobodnie.

Opcja applicationServerKey przekazywana do wywołania subscribe() jest publiczną aplikacją . Przeglądarka przekazuje go do usługi push podczas subskrybowania użytkownika, co oznacza usługa może powiązać klucz publiczny aplikacji z PushSubscription użytkownika.

Schemat poniżej ilustruje te kroki.

  1. Twoja aplikacja internetowa jest wczytywana w przeglądarce i wywołuje funkcję subscribe(), przekazując ją publicznie klucza serwera aplikacji.
  2. Następnie przeglądarka wysyła żądanie sieciowe do usługi push, która generuje punkt końcowy. powiąż ten punkt końcowy z kluczem publicznym aplikacji i zwróć punkt końcowy do przeglądarki.
  3. Przeglądarka doda ten punkt końcowy do PushSubscription, który jest zwracany przez metodę subscribe().

Ilustracja publicznego klucza serwera aplikacji używany w subskrybowaniu
.

Jeśli później zechcesz wysłać wiadomość push, musisz utworzyć nagłówek Authorization który będzie zawierał informacje podpisane kluczem prywatnym serwera aplikacji. Gdy usługa push otrzymuje żądanie wysłania wiadomości push, może zweryfikować ten podpisany nagłówek Authorization wyszukując klucz publiczny połączony z punktem końcowym odbierającym żądanie. Jeśli podpis to prawidłowy, dla usługi push wie, że musi pochodzić z serwera aplikacji z kluczem prywatnym. To w zasadzie takie zabezpieczenie, które uniemożliwia innym wysyłane do użytkowników aplikacji.

Sposób wykorzystania klucza prywatnego serwera aplikacji podczas wysyłania
wiadomość

Z technicznego punktu widzenia atrybut applicationServerKey jest opcjonalny. Najłatwiej jednak wymaga go wdrożenie w Chrome, a inne przeglądarki mogą go wymagać przyszłości. W przeglądarce Firefox jest opcjonalny.

Specyfikacja określająca, jaki powinien być klucz serwera aplikacji specyfikację VAPID. Za każdym razem, gdy przeczytasz tekst odnoszący się do „kluczy serwera aplikacji” lub „Klucze VAPID” – pamiętaj, że to jest to samo.

Jak tworzyć klucze serwera aplikacji

Publiczny i prywatny zestaw kluczy serwera aplikacji możesz utworzyć, odwiedzając web-push-codelab.glitch.me lub możesz użyć wiersz poleceń web-push aby wygenerować klucze, wykonaj te czynności:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

Klucze wystarczy utworzyć dla danej aplikacji tylko raz. Pamiętaj tylko, aby prywatny klucz prywatny. (Tak, właśnie to powiedziałem).

Uprawnienia i subscription()

Wywołanie funkcji subscribe() ma jeden efekt uboczny. Jeśli Twoja aplikacja internetowa nie ma uprawnień do wyświetlania powiadomień w momencie wywołania funkcji subscribe(), przeglądarka poprosi o żądanie i uprawnienia dostępu. Jest to przydatne, jeśli Twój interfejs działa z tym procesem, ale jeśli chcesz mieć więcej możliwości (jak myślę, większość deweloperów) trzymaj się interfejsu API Notification.requestPermission(). którą użyliśmy wcześniej.

Co to jest PushSubscription?

Nazywamy subscribe() i przekazujemy kilka opcji, a w zamian dostajemy obietnicę obejmującą PushSubscription w wyniku czego powstaje kod podobny do tego:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

Obiekt PushSubscription zawiera wszystkie wymagane informacje potrzebne do wysłania żądania push. wiadomości do tego użytkownika. Jeśli wydrukujesz treści za pomocą JSON.stringify(), pojawi się przycisk :

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint to adres URL usług push. Aby aktywować wiadomość push, wyślij żądanie POST do tego adresu URL.

Obiekt keys zawiera wartości używane do szyfrowania danych wiadomości wysyłanych za pomocą wiadomości push (którą omówimy później w tej sekcji).

Regularna ponowna subskrypcja w celu uniknięcia jej wygaśnięcia

Gdy subskrybujesz powiadomienia push, często otrzymujesz PushSubscription.expirationTime w wysokości null. Teoretycznie oznacza to, że subskrypcja nigdy nie wygasa (w przeciwieństwie do tego, że otrzymujesz DOMHighResTimeStamp, który wskazuje dokładny moment wygaśnięcia subskrypcji). W praktyce często jednak wygasają subskrypcje, na przykład gdy przez dłuższy czas nie otrzymujesz powiadomień push lub gdy przeglądarka wykryje, że użytkownik nie używa aplikacji, która ma uprawnienia do powiadomień push. Jednym z wzorców zapobiegających takiej sytuacji jest ponowne subskrybowanie użytkownika po każdym otrzymaniu powiadomienia, tak jak pokazano w tym fragmencie. Wymaga to wysyłania powiadomień na tyle często, aby przeglądarka nie wygasła automatycznie. Warto bardzo dokładnie rozważyć zalety i wady uzasadnionych potrzeb w zakresie powiadomień, aby uniknąć przypadkowego spamowania użytkownika, tak aby subskrypcja nie wygasła. Podsumowując, nie próbuj walczyć z przeglądarką, aby chronić użytkownika przed zapomnianymi subskrypcjami powiadomień.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Wyślij subskrypcję na swój serwer

Gdy masz już subskrypcję push, chcesz ją wysłać na swój serwer. To zależy od Ciebie to jednak tylko JSON.stringify(), by pobrać wszystkie niezbędne dane z obiektu subskrypcji. Możesz też połączyć w całości to samo wynik ręcznie, w ten sposób:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

Subskrypcję możesz wysłać na stronie internetowej w ten sposób:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

Serwer węzła odbiera to żądanie i zapisuje dane w bazie danych na potrzeby późniejszego użycia.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  return saveSubscriptionToDatabase(req.body)
    .then(function (subscriptionId) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({data: {success: true}}));
    })
    .catch(function (err) {
      res.status(500);
      res.setHeader('Content-Type', 'application/json');
      res.send(
        JSON.stringify({
          error: {
            id: 'unable-to-save-subscription',
            message:
              'The subscription was received but we were unable to save it to our database.',
          },
        }),
      );
    });
});

Mając dane PushSubscription na naszym serwerze, możemy wysłać do użytkownika wiadomość, kiedy tylko zechcemy.

Regularna ponowna subskrypcja w celu uniknięcia jej wygaśnięcia

Gdy subskrybujesz powiadomienia push, często otrzymujesz PushSubscription.expirationTime w wysokości null. Teoretycznie oznacza to, że subskrypcja nigdy nie wygasa (w przeciwieństwie do tego, że otrzymujesz DOMHighResTimeStamp, który wskazuje dokładny moment wygaśnięcia subskrypcji). W praktyce często jednak wygasają subskrypcje, na przykład gdy przez dłuższy czas nie odebrano powiadomień push lub gdy przeglądarka wykryje, że użytkownik nie korzysta z aplikacji z uprawnieniami do powiadomień push. Jednym z wzorców zapobiegających takiej sytuacji jest ponowne subskrybowanie użytkownika po każdym otrzymaniu powiadomienia, tak jak pokazano w tym fragmencie. Wymaga to wysyłania powiadomień na tyle często, by przeglądarka nie wygasła automatycznie. Warto bardzo dokładnie rozważyć zalety i wady uzasadnionych powiadomień, a tym samym spamowanie użytkownika, aby subskrypcja nie wygasła. Podsumowując, nie próbuj walczyć z przeglądarką, aby chronić użytkownika przed zapomnianymi subskrypcjami powiadomień.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Najczęstsze pytania

Oto kilka często zadawanych pytań:

Czy mogę zmienić usługę push używaną w przeglądarce?

Nie. Usługa push jest wybierana przez przeglądarkę i zgodnie z subscribe(), przeglądarka będzie wysyłać żądania sieciowe do usługi push aby pobrać szczegóły składające się na PushSubscription.

Każda przeglądarka korzysta z innej usługi Push. Czy nie mają one różnych interfejsów API?

Wszystkie usługi push będą oczekiwać tego samego interfejsu API.

Ten typowy interfejs API nosi nazwę Protokół Web Push Protocol i opisuje żądanie sieciowe, musi być utworzona aplikacja, aby aktywować komunikat push.

Czy jeśli subskrybuję użytkownika na komputerze, czy on też ma subskrypcję na telefonie?

Nie. Użytkownik musi zarejestrować się w usłudze push w każdej przeglądarce, dla odbierania wiadomości. Warto też zauważyć, że będzie to wymagać o których użytkownik przyznaje odpowiednie uprawnienia na każdym z urządzeń.

Co dalej

Ćwiczenia z kodowania