Envoi de données / charge utile à la notification Push Google Chrome avec Javascript

Je travaille sur Google Chrome Push Notification et j'essaie d'envoyer la charge utile au travail Google Chrome, mais je n'ai aucune idée de la façon dont je reçois cette charge utile.

J'ai une API pour créer et enregistrer les notifications dans ma base de données et j'ai besoin d'envoyer les valeurs via https://android.googleapis.com/gcm/send et recevoir sur le travailleur.js

C'est mon travailleur.js

  self.addEventListener('push', function(event) { var title = 'Yay a message.'; var body = 'We have received a push message.'; var icon = '/images/icon-192x192.png'; var tag = 'simple-push-demo-notification-tag'; event.waitUntil( self.registration.showNotification(title, { body: body, icon: icon, tag: tag }) ); }); 

Et c'est ainsi que j'appelle le GCM

 curl --header "Authorization: key=AIzaSyDQjYDxeS9MM0LcJm3oR6B7MU7Ad2x2Vqc" --header "Content-Type: application/json" https://android.googleapis.com/gcm/send -d "{ \"data\":{\"foo\":\"bar\"}, \"registration_ids\":[\"APA91bGqJpCmyCnSHLjY6STaBQEumz3eFY9r-2CHTtbsUMzBttq0crU3nEXzzU9TxNpsYeFmjA27urSaszKtA0WWC3yez1hhneLjbwJqlRdc_Yj1EiqLHluVwHB6V4FNdXdKb_gc_-7rbkYkypI3MtHpEaJbWsj6M5Pgs4nKqQ2R-WNho82mnRU\"]}" 

J'ai essayé d'obtenir event.data mais, c'est indéfini.

Est-ce que quelqu'un a une idée ou une suggestion?

Malheureusement, cela semble être un comportement intentionnel :

Un inconvénient de la mise en œuvre actuelle de l'API Push dans Chrome est que vous ne pouvez pas envoyer une charge utile avec un message push. Non, rien. La raison en est que, dans une future implémentation, la charge utile devra être chiffrée sur votre serveur avant qu'elle ne soit envoyée à un point d'extrémité de messagerie push. De cette façon, le point final, quel que soit le fournisseur de poussée, ne pourra pas facilement visualiser le contenu de la charge utile push. Cela protège également contre d'autres vulnérabilités comme une mauvaise validation des certificats HTTPS et des attaques man-in-the-middle entre votre serveur et le fournisseur push. Cependant, ce cryptage n'est pas encore pris en charge, alors, dans l'intervalle, vous devrez effectuer une demande d'extraction pour obtenir les informations nécessaires pour remplir une notification.

Comme indiqué ci-dessus, la solution de contournement est de contacter votre backend après avoir reçu la pression et récupérer les données stockées sur le serveur tiers.

La réponse de @ gauchofunky est correcte. Avec quelques conseils de la part du chromium dev slack channel et @gauchofunky, j'ai pu rassembler quelque chose. Voici comment contourner les limites actuelles; J'espère que ma réponse devient bientôt obsolète!

Tout d'abord, décrivez comment vous allez persister les notifications sur votre back-end. J'utilise Node / Express et MongoDB avec Mongoose et mon schéma ressemble à ceci:

 var NotificationSchema = new Schema({ _user: {type: mongoose.Schema.Types.ObjectId, ref: 'User'}, subscriptionId: String, title: String, body: String, sent: { type: Boolean, default: false } }); 

Assurez-vous d'ajouter une icône si vous souhaitez modifier l'icône. J'utilise la même icône chaque fois que le mien est codé en dur dans le travailleur du service.

Le fait de découvrir le bon service web REST a réfléchi. GET a semblé être un choix facile, mais l'appel pour obtenir une notification entraîne des effets secondaires, donc GET est sorti. J'ai fini par passer un POST à /api/notifications avec un corps de {subscriptionId: <SUBSCRIPTION_ID>} . Dans la méthode, nous effectuons essentiellement un dequeue:

 var subscriptionId = req.body.subscriptionId; Notification .findOne({_user: req.user, subscriptionId: subscriptionId, sent: false}) .exec(function(err, notification) { if(err) { return handleError(res, err); } notification.sent = true; notification.save(function(err) { if(err) { return handleError(res, err); } return res.status(201).json(notification); }); }); 

Dans le service après-vente, nous devons absolument obtenir l'abonnement avant de procéder à l' fetch .

 self.addEventListener('push', function(event) { event.waitUntil( self.registration.pushManager.getSubscription().then(function(subscription) { fetch('/api/notifications/', { method: 'post', headers: { 'Authorization': 'Bearer ' + self.token, 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(subscription) }) .then(function(response) { return response.json(); }) .then(function(data) { self.registration.showNotification(data.title, { body: data.body, icon: 'favicon-196x196.png' }); }) .catch(function(err) { console.log('err'); console.log(err); }); }) ); }); 

Il est également intéressant de noter que l'objet d'abonnement est passé de Chrome 43 à Chrome 45. Dans Chrome 45, la propriété subscriptionId été supprimée, juste à faire attention – ce code a été écrit pour fonctionner avec Chrome 43.

Je voulais faire des appels authentifiés sur mon backend, donc j'ai dû trouver comment obtenir le JWT de mon application Angular à mon agent de maintenance. J'ai fini par utiliser postMessage . Voici ce que je fais après l'enregistrement du serviceleur:

 navigator.serviceWorker.register('/service-worker.js', {scope:'./'}).then(function(reg) { var messenger = reg.installing || navigator.serviceWorker.controller; messenger.postMessage({token: $localStorage.token}); }).catch(function(err) { console.log('err'); console.log(err); }); 

Dans le serviceleur, écoutez le message:

 self.onmessage.addEventListener('message', function(event) { self.token = event.data.token; }); 

Curieusement, cet auditeur fonctionne dans Chrome 43 mais pas Chrome 45. Chrome 45 fonctionne avec un gestionnaire comme ceci:

 self.addEventListener('message', function(event) { self.token = event.data.token; }); 

À l'heure actuelle, les notifications push prennent un peu de travail pour que quelque chose soit utile – je suis vraiment impatient de faire des recherches!

En fait, la charge utile devrait être implémentée dans Chrome 50 (date de publication – 19 avril 2016). Dans Chrome 50 (et dans la version actuelle de Firefox sur le bureau), vous pouvez envoyer des données arbitraires avec la poussée afin que le client puisse éviter de faire la demande supplémentaire. Toutes les données de la charge utile doivent être cryptées.

Voici les détails de cryptage du développeur: https://developers.google.com/web/updates/2016/03/web-push-encryption?hl=fr

Je viens de rencontrer ce problème. Les dernières versions de firefox et chrome (version 50+) supportent le transfert de charge utile.

Le développeur détaille ici la mise en œuvre de la manière dont cela fonctionne. Une chose importante à noter est que google GCM ou éventuellement client / chome (je ne sais pas lequel) ignorerons la charge utile entièrement s'il n'est pas chiffré.

Ce site Web a les implémentations client / serveur de la façon de faire la recherche et la récupération par le biais des travailleurs du service. La bibliothèque push que les exemples utilisent est simplement une enveloppe autour d'un appel REST normal

Exploitation d'un exemple de travailleur de service :

 self.addEventListener('push', function(event) { var payload = event.data ? event.data.text() : 'no payload'; event.waitUntil( self.registration.showNotification('ServiceWorker Cookbook', { body: payload, }) ); }); 

Exemple d'implémentation d'exemple:

 var webPush = require('web-push'); webPush.setGCMAPIKey(process.env.GCM_API_KEY); module.exports = function(app, route) { app.post(route + 'register', function(req, res) { res.sendStatus(201); }); app.post(route + 'sendNotification', function(req, res) { setTimeout(function() { webPush.sendNotification(req.body.endpoint, { TTL: req.body.ttl, payload: req.body.payload, userPublicKey: req.body.key, userAuth: req.body.authSecret, }).then(function() { res.sendStatus(201); }); }, req.body.delay * 1000); }); }; 

Exemple d'implémentation javascript côté client pour imprimer les champs requis.

 navigator.serviceWorker.register('serviceWorker.js') .then(function(registration) { return registration.pushManager.getSubscription() .then(function(subscription) { if (subscription) { return subscription; } return registration.pushManager.subscribe({ userVisibleOnly: true }); }); }).then(function(subscription) { var rawKey = subscription.getKey ? subscription.getKey('p256dh') : ''; key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : ''; var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : ''; authSecret = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : ''; endpoint = subscription.endpoint; console.log("Endpoint: " + endpoint); console.log("Key: " + key); console.log("AuthSecret: " + authSecret); });