In questo codelab, creerai un server per le notifiche push. Il server gestirà un elenco di iscrizioni push a cui invierà notifiche.
Il codice client è già completo: in questo codelab lavorerai sulla funzionalità lato server.
Remixa l'app di esempio e visualizzala in una nuova scheda
Le notifiche vengono bloccate automaticamente dall'app Glitch incorporata, quindi non potrai visualizzare l'anteprima dell'app in questa pagina. Ecco invece cosa fare:
- Fai clic su Remixa per modificare per rendere modificabile il progetto.
- Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi
Schermo intero
.
L'app pubblicata si apre in una nuova scheda di Chrome. Nel glitch incorporato, fai clic su Visualizza sorgente per visualizzare nuovamente il codice.
Mentre lavori in questo codelab, apporta modifiche al codice nel Glitch incorporato in questa pagina. Aggiorna la nuova scheda con la tua app pubblicata per vedere le modifiche.
Acquisisci familiarità con l'app iniziale e il relativo codice
Inizia dando un'occhiata all'interfaccia utente client dell'app.
Nella nuova scheda di Chrome:
Premi "Ctrl+Maiusc+J" (o "Comando+Opzione+J" su Mac) per aprire DevTools. Fai clic sulla scheda Console.
Prova a fare clic sui pulsanti nell'interfaccia utente (controlla l'output nella console per sviluppatori di Chrome).
Registra service worker consente di registrare un service worker per l'ambito dell'URL del progetto Glitch. L'annullamento della registrazione del service worker lo rimuove. Se è collegata una sottoscrizione push, anche la sottoscrizione push verrà disattivata.
Abbonati per push crea una sottoscrizione push. È disponibile solo quando un service worker è stato registrato ed è presente una costante
VAPID_PUBLIC_KEY
nel codice client (ulteriori informazioni in merito più avanti), quindi non puoi ancora fare clic su questa opzione.Se hai una sottoscrizione push attiva, Invia notifica all'abbonamento attuale richiede che il server invii una notifica al suo endpoint.
Notifica tutte le sottoscrizioni indica al server di inviare una notifica a tutti gli endpoint di sottoscrizione nel suo database.
Tieni presente che alcuni di questi endpoint potrebbero non essere attivi. È sempre possibile che un abbonamento scompaia quando il server gli invia una notifica.
Vediamo cosa succede sul lato server. Per visualizzare i messaggi provenienti dal codice del server, esamina il log Node.js all'interno dell'interfaccia di Glitch.
Nell'app Glitch, fai clic su Strumenti -> Log.
Probabilmente visualizzerai un messaggio simile a
Listening on port 3000
.Se hai provato a fare clic su Invia notifica abbonamento attuale o Invia notifica a tutte le iscrizioni nell'interfaccia utente dell'app pubblicata, vedrai anche il seguente messaggio:
TODO: Implement sendNotifications() Endpoints to send to: []
Ora diamo un'occhiata al codice.
public/index.js
contiene il codice client completato. Esegue il rilevamento delle funzionalità, registra e annulla la registrazione del service worker e controlla l'iscrizione dell'utente alle notifiche push. Invia inoltre al server informazioni sugli abbonamenti nuovi ed eliminati.Dal momento che lavorerai solo sulla funzionalità del server, non modificherai questo file (a parte la compilazione della costante
VAPID_PUBLIC_KEY
).public/service-worker.js
è un semplice service worker che acquisisce gli eventi push e mostra le notifiche./views/index.html
contiene l'UI dell'app..env
contiene le variabili di ambiente che Glitch carica nel server delle app all'avvio. Compila.env
con i dettagli di autenticazione per l'invio di notifiche.server.js
è il file in cui svolgerai la maggior parte del lavoro durante questo codelab.Il codice iniziale crea un semplice server web Express. Esistono quattro elementi TODO per te, contrassegnati nei commenti del codice con
TODO:
. Tu devi:In questo codelab, lavorerai su questi elementi TODO uno alla volta.
Genera e carica dettagli VAPID
Il primo elemento da fare è generare dettagli VAPID, aggiungerli alle variabili di ambiente Node.js e aggiornare il codice del client e del server con i nuovi valori.
Sfondo
Quando gli utenti si iscrivono alle notifiche, devono considerare attendibile l'identità dell'app e del suo server. Inoltre, gli utenti devono essere sicuri che quando ricevono una notifica provenga dalla stessa app che ha configurato l'abbonamento. Devono inoltre avere la certezza che nessun altro potrà leggere i contenuti delle notifiche.
Il protocollo che rende sicure e private le notifiche push è denominato VAPID (Voluntary Application Server Identification for Web Push). VAPID utilizza la crittografia a chiave pubblica per verificare l'identità di app, server ed endpoint di abbonamento e per criptare i contenuti delle notifiche.
In questa app utilizzerai il pacchetto npm web-push per generare chiavi VAPID, nonché per criptare e inviare notifiche.
Implementazione
In questo passaggio, genera una coppia di chiavi VAPID per la tua app e aggiungile alle variabili di ambiente. Carica le variabili di ambiente sul server e aggiungi la chiave pubblica come costante nel codice client.
Usa la funzione
generateVAPIDKeys
della libreriaweb-push
per creare una coppia di chiavi VAPID.In server.js, rimuovi i commenti dalle seguenti righe di codice:
server.js
// Generate VAPID keys (only do this once). /* * const vapidKeys = webpush.generateVAPIDKeys(); * console.log(vapidKeys); */ const vapidKeys = webpush.generateVAPIDKeys(); console.log(vapidKeys);
Dopo il riavvio dell'app, Glitch invia le chiavi generate nel log Node.js all'interno dell'interfaccia di Glitch (non nella console di Chrome). Per visualizzare le chiavi VAPID, seleziona Strumenti -> Log nell'interfaccia di Glitch.
Assicurati di copiare le chiavi pubbliche e private dalla stessa coppia di chiavi.
Glitch riavvia l'app ogni volta che modifichi il codice, quindi la prima coppia di chiavi generate potrebbe scorrere fuori dalla visualizzazione man mano che segue altri output.
In .env, copia e incolla le chiavi VAPID. Racchiudi le chiavi tra virgolette doppie (
"..."
).Per
VAPID_SUBJECT
, puoi inserire"mailto:test@test.test"
..env
# process.env.SECRET VAPID_PUBLIC_KEY= VAPID_PRIVATE_KEY= VAPID_SUBJECT= VAPID_PUBLIC_KEY="BN3tWzHp3L3rBh03lGLlLlsq..." VAPID_PRIVATE_KEY="I_lM7JMIXRhOk6HN..." VAPID_SUBJECT="mailto:test@test.test"
In server.js, commenta di nuovo queste due righe di codice, dato che è necessario generare le chiavi VAPID una sola volta.
server.js
// Generate VAPID keys (only do this once). /* const vapidKeys = webpush.generateVAPIDKeys(); console.log(vapidKeys); */ const vapidKeys = webpush.generateVAPIDKeys(); console.log(vapidKeys);
In server.js, carica i dettagli VAPID dalle variabili di ambiente.
server.js
const vapidDetails = { // TODO: Load VAPID details from environment variables. publicKey: process.env.VAPID_PUBLIC_KEY, privateKey: process.env.VAPID_PRIVATE_KEY, subject: process.env.VAPID_SUBJECT }
Copia e incolla la chiave public anche nel codice client.
In public/index.js, inserisci per
VAPID_PUBLIC_KEY
lo stesso valore che hai copiato nel file .env:public/index.js
// Copy from .env const VAPID_PUBLIC_KEY = ''; const VAPID_PUBLIC_KEY = 'BN3tWzHp3L3rBh03lGLlLlsq...'; ````
Implementare la funzionalità per l'invio di notifiche
Sfondo
In questa app, utilizzerai il pacchetto npm web-push per inviare notifiche.
Questo pacchetto cripta automaticamente le notifiche quando viene chiamata webpush.sendNotification()
, quindi non devi preoccuparti di questo.
web-push accetta più opzioni per le notifiche: ad esempio, è possibile allegare intestazioni al messaggio e specificare la codifica dei contenuti.
In questo codelab, utilizzerai solo due opzioni, definite con le seguenti righe di codice:
let options = {
TTL: 10000; // Time-to-live. Notifications expire after this.
vapidDetails: vapidDetails; // VAPID keys from .env
};
L'opzione TTL
(durata) imposta un timeout di scadenza per una notifica. In questo modo il server evita di inviare una notifica a un utente quando non è più pertinente.
L'opzione vapidDetails
contiene le chiavi VAPID che hai caricato dalle variabili di ambiente.
Implementazione
In server.js, modifica la funzione sendNotifications
come segue:
server.js
function sendNotifications(database, endpoints) {
// TODO: Implement functionality to send notifications.
console.log('TODO: Implement sendNotifications()');
console.log('Endpoints to send to: ', endpoints);
let notification = JSON.stringify(createNotification());
let options = {
TTL: 10000, // Time-to-live. Notifications expire after this.
vapidDetails: vapidDetails // VAPID keys from .env
};
endpoints.map(endpoint => {
let subscription = database[endpoint];
webpush.sendNotification(subscription, notification, options);
});
}
Poiché webpush.sendNotification()
restituisce una promessa, puoi facilmente aggiungere la gestione degli errori.
In server.js, modifica nuovamente la funzione sendNotifications
:
server.js
function sendNotifications(database, endpoints) {
let notification = JSON.stringify(createNotification());
let options = {
TTL: 10000; // Time-to-live. Notifications expire after this.
vapidDetails: vapidDetails; // VAPID keys from .env
};
endpoints.map(endpoint => {
let subscription = database[endpoint];
webpush.sendNotification(subscription, notification, options);
let id = endpoint.substr((endpoint.length - 8), endpoint.length);
webpush.sendNotification(subscription, notification, options)
.then(result => {
console.log(`Endpoint ID: ${id}`);
console.log(`Result: ${result.statusCode} `);
})
.catch(error => {
console.log(`Endpoint ID: ${id}`);
console.log(`Error: ${error.body} `);
});
});
}
Gestire i nuovi abbonamenti
Sfondo
Ecco cosa succede quando l'utente si iscrive alle notifiche push:
L'utente fa clic su Abbonati per push.
Il client utilizza la costante
VAPID_PUBLIC_KEY
(la chiave VAPID pubblica del server) per generare un oggettosubscription
univoco e specifico del server. L'oggettosubscription
ha il seguente aspetto:{ "endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9...", "expirationTime": null, "keys": { "p256dh": "BNYDjQL9d5PSoeBurHy2e4d4GY0sGJXBN...", "auth": "0IyyvUGNJ9RxJc83poo3bA" } }
Il client invia una richiesta
POST
all'URL/add-subscription
, inclusa la sottoscrizione sotto forma di JSON con stringa nel corpo.Il server recupera l'elemento
subscription
in formato stringa dal corpo della richiesta POST, lo analizza nuovamente in JSON e lo aggiunge al database degli abbonamenti.Il database archivia le sottoscrizioni utilizzando i propri endpoint come chiave:
{
"https://fcm...1234": {
endpoint: "https://fcm...1234",
expirationTime: ...,
keys: { ... }
},
"https://fcm...abcd": {
endpoint: "https://fcm...abcd",
expirationTime: ...,
keys: { ... }
},
"https://fcm...zxcv": {
endpoint: "https://fcm...zxcv",
expirationTime: ...,
keys: { ... }
},
}
Ora il nuovo abbonamento è disponibile per il server per l'invio di notifiche.
Implementazione
Le richieste di nuovi abbonamenti arrivano alla route /add-subscription
, che è un URL POST. Vedrai un gestore di route stub in server.js:
server.js
app.post('/add-subscription', (request, response) => {
// TODO: implement handler for /add-subscription
console.log('TODO: Implement handler for /add-subscription');
console.log('Request body: ', request.body);
response.sendStatus(200);
});
Nella tua implementazione, questo gestore deve:
- Recupera la nuova sottoscrizione dal corpo della richiesta.
- Accedi al database degli abbonamenti attivi.
- Aggiungi il nuovo abbonamento all'elenco degli abbonamenti attivi.
Per gestire i nuovi abbonamenti:
In server.js, modifica il gestore della route per
/add-subscription
come segue:server.js
app.post('/add-subscription', (request, response) => {
// TODO: implement handler for /add-subscription
console.log('TODO: Implement handler for /add-subscription');
console.log('Request body: ', request.body);
let subscriptions = Object.assign({}, request.session.subscriptions);
subscriptions[request.body.endpoint] = request.body;
request.session.subscriptions = subscriptions;
response.sendStatus(200);
});
Gestire gli annullamenti degli abbonamenti
Sfondo
Il server non saprà sempre quando un abbonamento diventa inattivo: ad esempio, un abbonamento potrebbe essere cancellato quando il browser arresta il service worker.
Tuttavia, il server può scoprire gli abbonamenti annullati tramite l'interfaccia utente dell'app. In questo passaggio, implementerai la funzionalità per rimuovere una sottoscrizione dal database.
In questo modo, il server evita di inviare una serie di notifiche a endpoint inesistenti. Ovviamente, questo non importa in realtà con una semplice app di test, ma diventa importante su scala più ampia.
Implementazione
Le richieste di annullamento degli abbonamenti arrivano all'URL POST di /remove-subscription
.
Il gestore della route stub in server.js ha il seguente aspetto:
server.js
app.post('/remove-subscription', (request, response) => {
// TODO: implement handler for /remove-subscription
console.log('TODO: Implement handler for /remove-subscription');
console.log('Request body: ', request.body);
response.sendStatus(200);
});
Nella tua implementazione, questo gestore deve:
- Recupera l'endpoint dell'abbonamento annullato dal corpo della richiesta.
- Accedi al database degli abbonamenti attivi.
- Rimuovi l'abbonamento annullato dall'elenco degli abbonamenti attivi.
Il corpo della richiesta POST dal client contiene l'endpoint che devi rimuovere:
{
"endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9..."
}
Per gestire l'annullamento degli abbonamenti:
In server.js, modifica il gestore della route per
/remove-subscription
come segue:server.js
app.post('/remove-subscription', (request, response) => {
// TODO: implement handler for /remove-subscription
console.log('TODO: Implement handler for /remove-subscription');
console.log('Request body: ', request.body);
let subscriptions = Object.assign({}, request.session.subscriptions);
delete subscriptions[request.body.endpoint];
request.session.subscriptions = subscriptions;
response.sendStatus(200);
});