JavaScript Push API e Notifiche
La Push API in JavaScript è uno strumento essenziale per migliorare le applicazioni web con notifiche in tempo reale, integrata con i service worker.
Introduzione alla Push API in JavaScript
La Push API in JavaScript consente a un'applicazione web di ricevere messaggi inviati da un server, anche quando la pagina è chiusa o il browser è in background. È la base delle notifiche push web: avvisi di notizie, messaggi di chat e promemoria di re-engagement che arrivano senza che l'utente mantenga una scheda aperta.
La Push API non funziona mai da sola. Si basa su altre due funzionalità del browser:
- Un service worker — uno script in background che rimane attivo dopo la chiusura della pagina e riceve il push.
- La Notifications API — ciò che il service worker utilizza per mostrare effettivamente il messaggio all'utente.
Questa pagina illustra il flusso completo lato client: registrazione di un service worker, richiesta del permesso, sottoscrizione con una chiave VAPID, ricezione del push nel service worker e visualizzazione di una notifica. Spiega inoltre il ruolo del server.
Come funziona il flusso push
Il percorso end-to-end di un singolo messaggio push è il seguente:
- La tua pagina registra un service worker e si iscrive al push. Il browser restituisce un oggetto
PushSubscriptioncontenente un URL endpoint univoco. - La tua pagina invia quella sottoscrizione al tuo server e la memorizza.
- In seguito, il tuo server firma un messaggio con la sua chiave privata VAPID e lo invia all'endpoint della sottoscrizione, che appartiene a un Push Service del fornitore (Mozilla, Google, Apple, ecc.).
- Il Push Service risveglia il browser dell'utente e attiva un evento
pushnel tuo service worker. - Il service worker mostra una notifica in risposta.
La Push API richiede un contesto sicuro: la pagina deve essere servita tramite HTTPS (localhost è considerato sicuro per lo sviluppo). Senza di esso, navigator.serviceWorker e PushManager non sono disponibili.
Implementare le Notifiche Push
Configurare i Service Worker
Per prima cosa, è necessario registrare un service worker che gestisce le attività in background per l'invio delle notifiche:
// Registering a service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
}).catch(function(error) {
console.log('Service Worker registration failed:', error);
});
}Richiedere il Permesso per le Notifiche
Prima di inviare notifiche, è necessario richiedere il permesso all'utente. La richiesta deve essere attivata da un gesto dell'utente (ad esempio un clic) — i browser rifiutano le richieste di permesso che si attivano automaticamente al caricamento della pagina:
<button id="enable-notif-btn">Enable Notifications</button>
<script>
// Asking user permission for notifications
function requestPermission() {
Notification.requestPermission().then(function(permission) {
console.log('Notification permission:', permission);
});
}
document.getElementById('enable-notif-btn').addEventListener('click', requestPermission);
</script>Sottoscriversi alle Notifiche Push
Dopo aver ottenuto il permesso, l'applicazione può iscriversi alle notifiche push. L'applicationServerKey deve essere un Uint8Array, non la stringa base64 che di solito si memorizza — è quindi necessario convertirla prima. VAPID (Voluntary Application Server Identification) è la coppia di chiavi che consente al Push Service di verificare che i push provengano davvero dal tuo server: la chiave pubblica va qui, la chiave privata rimane nel backend.
<button id="subscribe-btn">Subscribe to Push Notifications</button>
<script>
// The VAPID public key arrives as a base64url string; the API needs a Uint8Array.
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
const raw = atob(base64);
return Uint8Array.from([...raw].map(c => c.charCodeAt(0)));
}
const VAPID_PUBLIC_KEY = 'YOUR_VAPID_PUBLIC_KEY'; // base64url string from your server
function subscribeToPush() {
navigator.serviceWorker.ready.then(function(registration) {
// userVisibleOnly: true is required — the browser rejects silent push subscriptions.
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
});
})
.then(function(subscription) {
console.log('Push subscription:', JSON.stringify(subscription));
// Send the subscription to your backend so it can push to this user later.
return fetch('/api/save-subscription', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
})
.catch(function(error) {
console.log('Failed to subscribe to push:', error);
});
}
document.getElementById('subscribe-btn').addEventListener('click', subscribeToPush);
</script>Un PushSubscription viene serializzato in JSON contenente l'URL endpoint e le keys di cifratura (p256dh e auth). Il tuo server ha bisogno di tutti questi dati per inviare un messaggio. Impostare userVisibleOnly: true è obbligatorio nei browser attuali: garantisce che ogni push darà origine a una notifica visibile all'utente, motivo per cui i push silenziosi in background non sono consentiti sul web.
Gestire i Messaggi Push in Arrivo
Per gestire i messaggi in arrivo, il service worker ascolta gli eventi push. Il payload inviato arriva su event.data; usa event.data.json() (oppure .text()) per leggerlo. Inserire showNotification() dentro event.waitUntil() mantiene il service worker attivo fino a quando la notifica non viene visualizzata:
// Inside service-worker.js
self.addEventListener('push', function(event) {
// Read the payload your server sent (fall back gracefully if there is none).
var payload = event.data ? event.data.json() : {};
var options = {
body: payload.body || 'New notification.',
icon: 'icon.png',
vibrate: [100, 50, 100],
data: { primaryKey: 1 }
};
event.waitUntil(
self.registration.showNotification(payload.title || 'Push Notification', options)
);
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(
clients.openWindow('https://example.com')
);
});
self.addEventListener('pushsubscriptionchange', function(event) {
console.log('Subscription changed, re-subscribing...');
// Re-subscribe using the same parameters
event.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: 'YOUR_VAPID_PUBLIC_KEY'
}).then(function(newSubscription) {
console.log('Re-subscribed:', newSubscription);
}).catch(function(error) {
console.error('Re-subscription failed:', error);
});
});Questo snippet mostra i tre eventi da gestire: push (mostra la notifica), notificationclick (mette a fuoco o apre una finestra quando l'utente fa clic), e pushsubscriptionchange (ri-sottoscrive quando il browser ruota la sottoscrizione).
Il Ruolo del Server
Il browser non può inviare push a se stesso — ogni messaggio ha origine dal backend. Il server conserva la chiave privata VAPID e, per ogni sottoscrizione memorizzata, invia una richiesta HTTP cifrata e firmata all'endpoint della sottoscrizione. In pratica si utilizza una libreria web-push (ad esempio web-push su Node.js) invece di costruire la cifratura manualmente:
// Server side (Node.js) — conceptual example
const webpush = require('web-push');
webpush.setVapidDetails(
'mailto:[email protected]',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);
// `subscription` is the JSON object the browser sent to /api/save-subscription
const payload = JSON.stringify({ title: 'Hello', body: 'You have a new message.' });
webpush.sendNotification(subscription, payload)
.catch(err => console.error('Push failed:', err.statusCode));Una risposta 410 Gone o 404 significa che la sottoscrizione è scaduta — eliminala dal database. Questo è il corrispettivo lato server della gestione di pushsubscriptionchange sul client.
Best Practice per le Notifiche Push
- Coinvolgimento dell'utente: Progetta le notifiche in modo che siano tempestive, pertinenti e precise.
- Conformità alla privacy: Assicurati sempre di ottenere il consenso dell'utente prima di inviare notifiche.
- Prestazioni: Gestisci la frequenza e i tempi delle notifiche per evitare di sovraccaricare l'utente.
- Rinnovo della sottoscrizione: Le sottoscrizioni push scadono periodicamente. Implementa logica lato client per verificare lo stato della sottoscrizione e ri-sottoscrivere quando necessario, oppure gestisci gli eventi di scadenza dal service worker.
Conclusione
La Push API apre un canale di interazione diretta con gli utenti, offrendo un potente strumento di coinvolgimento. Sfruttando questa API, gli sviluppatori possono offrire un'esperienza utente più dinamica e reattiva. Un'implementazione corretta delle notifiche push può migliorare significativamente le funzionalità e l'attrattiva delle applicazioni web, mantenendo gli utenti informati e coinvolti.