Iscrizione di un utente

Matt Gaunt

Il primo passo è ottenere l'autorizzazione dall'utente per inviargli messaggi push e poi possiamo mettere le mani su un PushSubscription.

L'API JavaScript per eseguire questa operazione è ragionevolmente semplice, quindi attraverso il flusso logico.

Rilevamento delle caratteristiche

Per prima cosa dobbiamo verificare se il browser corrente supporta effettivamente i messaggi push. Possiamo verificare se il push è supportato con due semplici controlli.

  1. Controlla serviceWorker su navigator.
  2. Seleziona PushManager in finestra.
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;
}

Il supporto dei browser sta crescendo rapidamente sia per i service worker che per push dei messaggi, è sempre opportuno rilevare le funzionalità sia per migliorare progressivamente

Registra un service worker

Grazie al rilevamento delle funzionalità, sappiamo che sono supportati sia i service worker sia il push. Il passaggio successivo è "registrarsi" al nostro service worker.

Quando registriamo un service worker, comunichiamo al browser dove si trova il file del nostro service worker. Il file è ancora solo JavaScript, ma il browser "gli concede l'accesso" al service worker API, incluso il push. Per essere più precisi, il browser esegue il file in un service worker completamente gestito di Google Cloud.

Per registrare un service worker, chiama navigator.serviceWorker.register(), passando nel percorso di il nostro file. In questo modo:

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);
    });
}

Questa funzione indica al browser che è presente un file dei service worker e dove si trova. Nella in questo caso, il file del service worker si trova all'indirizzo /service-worker.js. Dietro le quinte, il browser dopo aver chiamato register():

  1. Scarica il file del service worker.

  2. Esegui il codice JavaScript.

  3. Se tutto funziona correttamente e non sono presenti errori, la promessa è stata restituita da register() verrà risolto. In caso di errori di qualsiasi tipo, la promessa viene rifiutata.

Se register() rifiuta, verifica che non ci siano errori di battitura o di errore in Chrome DevTools.

Quando register() viene risolto, restituisce un ServiceWorkerRegistration. Lo utilizzeremo la registrazione per accedere all'API PushManager.

Compatibilità del browser con l'API PushManager

Supporto dei browser

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

Origine

Richiesta autorizzazione in corso...

Abbiamo registrato il nostro service worker e siamo pronti a sottoscrivere l'abbonamento per l'utente, il passaggio successivo consiste nel l'autorizzazione da parte dell'utente per inviargli messaggi push.

L'API per ottenere le autorizzazioni è relativamente semplice, lo svantaggio è che l'API di recente è passata dal callback alla restituzione di una promessa. La problema è che non riusciamo a capire quale versione dell'API è implementata dalla nel browser web, quindi devi implementarli e gestirli entrambi.

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.");
    }
  });
}

Nel codice riportato sopra, lo snippet di codice importante è la chiamata Notification.requestPermission(). Questo metodo mostrerà un prompt all'utente:

Richiesta di autorizzazione su Chrome per computer e dispositivi mobili.

Dopo che l'utente ha interagito con la richiesta di autorizzazione premendo Consenti, Blocca o chiudendola, il risultato verrà fornito sotto forma di stringa: 'granted', 'default' o 'denied'.

Nel codice campione precedente, la promessa restituita da askPermission() si risolve se l'autorizzazione viene concessa, altrimenti viene restituito un errore nel tentativo di rifiutare la promessa.

Un caso limite che devi gestire è quando l'utente fa clic sul pulsante "Blocca" . Se questo la tua app web non potrà più chiedere l'autorizzazione all'utente. Dovranno "sbloccare" manualmente la tua app modificando lo stato di autorizzazione, che è nascosto in un riquadro delle impostazioni. Rifletti attentamente su come e quando chiedi l'autorizzazione all'utente. perché se fanno clic su Blocca, non è facile annullare questa decisione.

La buona notizia è che la maggior parte degli utenti è lieta di concedere l'autorizzazione, purché sanno perché viene richiesta l'autorizzazione.

Più avanti vedremo come alcuni siti popolari chiedono l'autorizzazione.

Iscrivere un utente con PushManager

Una volta registrato il Service worker e ottenuto l'autorizzazione, possiamo iscrivere un utente chiamata 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;
    });
}

Quando chiamiamo il metodo subscribe(), passiamo in un oggetto options, che è composto da parametri obbligatori e facoltativi.

Diamo un'occhiata a tutte le opzioni che possiamo passare.

Opzioni userVisibileOnly

Quando è stato aggiunto per la prima volta il push ai browser, non c'era incertezza sull'opportunità di in grado di inviare un messaggio push e non mostrare una notifica. Questa modalità è comunemente definita silenzioso perché l'utente non sapeva che è successo qualcosa in background.

Il problema era che gli sviluppatori potessero eseguire azioni dannose, ad esempio monitorare la posizione di un utente su una senza che l'utente lo sappia.

Per evitare questo scenario e concedere agli autori delle specifiche il tempo di considerare il modo migliore per supportarlo caratteristica, è stata aggiunta l'opzione userVisibleOnly e il passaggio del valore true è un valore simbolico accettando con il browser che l'app web mostri una notifica ogni volta che viene eseguito un push. ricevuto (ovvero nessun push silenzioso).

Al momento devi trasferire un valore pari a true. Se non includi il parametro userVisibleOnly chiave o pass in false riceverà il seguente errore:

Al momento Chrome supporta l'API Push solo per gli abbonamenti che comporteranno messaggi visibili all'utente. Puoi indicare questa informazione chiamando pushManager.subscribe({userVisibleOnly: true}) in alternativa. Consulta https://goo.gl/yqv4Q4 per maggiori dettagli.

Al momento sembra che il push silenzioso generale non verrà mai implementato in Chrome. Invece, gli autori delle specifiche stanno esplorando la nozione di API budget che consentirà alle app web di Numero di messaggi push silenziosi in base all'utilizzo di un'app web.

opzione applicationServerKey

Abbiamo accennato brevemente alle "chiavi del server delle applicazioni" nella sezione precedente. "Applicazione chiavi server". sono utilizzati da un servizio push per identificare l'applicazione che sottoscrive un utente assicurarsi che la stessa applicazione invii messaggi a quell'utente.

Le chiavi server delle applicazioni sono una coppia di chiavi pubbliche e private univoche per la tua applicazione. La chiave privata deve essere tenuta segreta per l'applicazione e la chiave pubblica può essere condivisa. libertà.

L'opzione applicationServerKey passata alla chiamata subscribe() è pubblica dell'applicazione chiave. Il browser lo passa a un servizio push quando iscrive l'utente, il che significa che il push può collegare la chiave pubblica della tua applicazione al valore PushSubscription dell'utente.

Il diagramma seguente illustra questi passaggi.

  1. La tua app web viene caricata in un browser e tu chiami subscribe(), passando il tuo pubblico la chiave server delle applicazioni.
  2. Il browser invia quindi una richiesta di rete a un servizio push che genererà un endpoint. associare questo endpoint alla chiave pubblica dell'applicazione e restituirlo alla del browser.
  3. Il browser aggiungerà questo endpoint a PushSubscription, che viene restituito tramite subscribe() promessa.

Illustrazione della chiave pubblica del server delle applicazioni che viene utilizzata nella sottoscrizione
.

Quando in seguito vorrai inviare un messaggio push, dovrai creare un'intestazione Authorization che conterrà informazioni firmate con la chiave privata del server delle applicazioni. Quando servizio push riceve una richiesta di invio di un messaggio push, può convalidare questa intestazione Authorization firmata cercando la chiave pubblica collegata all'endpoint che riceve la richiesta. Se la firma è valido, il servizio push sa che deve provenire dal server delle applicazioni chiave privata corrispondente. Si tratta essenzialmente di una misura di sicurezza che impedisce a chiunque altro di inviare inviati agli utenti di un'applicazione.

In che modo viene utilizzata la chiave privata del server delle applicazioni per l'invio di un
messaggio

Tecnicamente, il campo applicationServerKey è facoltativo. Tuttavia, il modello di implementazione su Chrome lo richiede, mentre altri browser potrebbero richiederlo in per il futuro. È facoltativo su Firefox.

La specifica che definisce la chiave del server delle applicazioni secondo le specifiche VAPID. Ogni volta che leggi qualcosa che fa riferimento a "chiavi server delle applicazioni" o "Chiavi VAPID", ricorda però che sono la stessa cosa.

Come creare chiavi server delle applicazioni

Puoi creare un set di chiavi del server delle applicazioni pubblico e privato visitando la pagina web-push-codelab.glitch.me oppure puoi utilizzare riga di comando web-push per generare le chiavi nel seguente modo:

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

Devi creare queste chiavi una sola volta per l'applicazione, assicurati solo di tenere privata chiave privata. (Sì, l'ho appena detto.)

Autorizzazioni e Subscribe()

Esiste un effetto collaterale della chiamata a subscribe(). Se la tua app web non dispone delle autorizzazioni per mostrare notifiche al momento della chiamata al numero subscribe(), il browser richiederà le autorizzazioni per te. Ciò è utile se la tua UI funziona con questo flusso, ma se vuoi più (come credo gran parte degli sviluppatori), seguirà l'API Notification.requestPermission() che abbiamo usato prima.

Che cos'è una sottoscrizione push?

Chiamiamo subscribe(), passiamo alcune opzioni e in cambio otteniamo una promessa che si risolve in una PushSubscription generando codice simile a questo:

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;
    });
}

L'oggetto PushSubscription contiene tutte le informazioni richieste per inviare un push a quell'utente. Se stampi i contenuti utilizzando JSON.stringify(), vedrai l'icona seguenti:

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

endpoint è l'URL dei servizi push. Per attivare un messaggio push, effettua una richiesta POST a questo URL.

L'oggetto keys contiene i valori utilizzati per criptare i dati dei messaggi inviati con un messaggio push (di cui parleremo più avanti in questa sezione).

Rinnovo regolare dell'abbonamento per evitare la scadenza

Quando ti iscrivi alle notifiche push, spesso ricevi un PushSubscription.expirationTime di null. In teoria, ciò significa che l'abbonamento non scade mai (a differenza di quando ricevi un DOMHighResTimeStamp, che ti indica il momento esatto in cui scade l'abbonamento). In pratica, tuttavia, capita spesso che i browser lascino scadere le iscrizioni, ad esempio se non vengono ricevute notifiche push per un periodo di tempo più lungo o se il browser rileva che l'utente non sta utilizzando un'app che dispone dell'autorizzazione per le notifiche push. Un metodo per evitare che ciò accada è ripetere l'iscrizione dell'utente a ogni notifica ricevuta, come mostrato nello snippet seguente. Ciò richiede che le notifiche vengano inviate con una frequenza sufficiente a far sì che il browser non scada automaticamente l'abbonamento e dovresti valutare con attenzione i vantaggi e gli svantaggi delle legittime richieste di notifica rispetto all'invio involontario di spam all'utente solo per evitare che l'abbonamento scada. In fin dei conti, non dovresti cercare di contrastare il browser nel suo tentativo di proteggere l'utente da iscrizioni a notifiche dimenticate da tempo.

/* 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);
    });
}

Invia una sottoscrizione al tuo server

Una volta che disponi di una sottoscrizione push, devi inviarla al tuo server. Sta a te decidere come farlo, ma un piccolo consiglio è quello di utilizzare JSON.stringify() per estrarre tutti i dati necessari abbonamento. In alternativa, puoi mettere insieme risultato manualmente in questo modo:

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);

L'invio dell'iscrizione viene effettuato nella pagina web in questo modo:

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.');
      }
    });
}

Il server nodo riceve questa richiesta e salva i dati in un database per utilizzarli in seguito.

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.',
          },
        }),
      );
    });
});

Con i dettagli PushSubscription sul nostro server, possiamo inviare all'utente un messaggio quando vogliamo.

Rinnovo regolare dell'abbonamento per evitare la scadenza

Quando ti iscrivi alle notifiche push, spesso ricevi un PushSubscription.expirationTime di null. In teoria, ciò significa che l'abbonamento non scade mai (a differenza di quando ricevi un DOMHighResTimeStamp, che ti indica il momento esatto in cui scade l'abbonamento). Nella pratica, tuttavia, capita spesso che i browser lascino scadere le iscrizioni, ad esempio se non vengono ricevute notifiche push per molto tempo o se il browser rileva che l'utente non sta utilizzando l'app che dispone dell'autorizzazione per le notifiche push. Un metodo per evitare che ciò accada è ripetere l'iscrizione dell'utente a ogni notifica ricevuta, come mostrato nello snippet seguente. Ciò richiede che le notifiche vengano inviate con una frequenza sufficiente a evitare che l'abbonamento sia scaduto automaticamente e bisognerà valutare con attenzione i vantaggi e gli svantaggi delle notifiche legittime, evitando di inviare spam all'utente solo per evitare che l'abbonamento scada. In fin dei conti, non dovresti cercare di contrastare il browser nel suo tentativo di proteggere l'utente da iscrizioni a notifiche dimenticate da tempo.

/* 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);
    });
}

Domande frequenti

Ecco alcune domande comuni che si sono poste a questo punto:

Posso cambiare il servizio push utilizzato da un browser?

No. Il servizio push viene selezionato dal browser e, come abbiamo visto con Chiamata subscribe(), il browser effettuerà richieste di rete al servizio push per recuperare i dettagli che compongono PushSubscription.

Ogni browser utilizza un servizio push diverso. Non hanno API differenti?

Tutti i servizi push si aspettano la stessa API.

Questa API comune è denominata Protocollo web push e descrive la richiesta di rete che l'applicazione deve eseguire per attivare un messaggio push.

Se mi iscrivo a un utente da un computer desktop, l'iscrizione viene effettuata anche sul suo telefono?

Purtroppo no. L'utente deve registrarsi per il push su ogni browser che vuole per la ricezione dei messaggi. Vale anche la pena notare che questo richiederà all'utente che concede l'autorizzazione su ciascun dispositivo.

Passaggi successivi

Codelab