Подтвердить что ты не робот

Отправка данных/полезной нагрузки в уведомление Google Chrome Push с помощью Javascript

Я работаю над уведомлением о переносе Google Chrome, и я пытаюсь отправить полезную нагрузку сотруднику Google Chrome, но я не знаю, как получить эту полезную нагрузку.

У меня есть API для создания и сохранения уведомлений в моей базе данных, и мне нужно отправить значения через https://android.googleapis.com/gcm/send и получить на work.js

Это мой worker.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
        })
      );
    });

И вот как я называю 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\"]}"

Я попытался получить event.data, но это undefined.

Есть ли у кого-нибудь идеи или предложения?

4b9b3361

Ответ 1

К сожалению, это похоже на предполагаемое поведение:

Недостатком текущей реализации Push API в Chrome является что вы не можете отправить полезную нагрузку с помощью push-сообщения. Нет, ничего. причина в том, что в будущей реализации полезная нагрузка будет иметь для шифрования на вашем сервере до его отправки в push-сообщение конечная точка. Таким образом, конечная точка, независимо от того, какой провайдер провайдера будет не иметь возможности легко просматривать содержимое полезной нагрузки push. Это также защищает от других уязвимостей, таких как плохая проверка HTTPS сертификаты и атаки "человек-в-середине" между вашим сервером и нажмите провайдера. Однако это шифрование еще не поддерживается, поэтому в тем временем вам нужно выполнить запрос на выборку, чтобы получить информацию необходимо заполнить уведомление.

Как указано выше, обходной путь заключается в том, чтобы связаться с вашим backend после получения push и получить сохраненные данные на стороннем сервере.

Ответ 2

@gauchofunky ответ правильный. С некоторым руководством от людей на канале Chromium Dev Slack и @gauchofunky я смог собрать что-то вместе. Здесь, как обойти текущие ограничения; надеюсь, мой ответ скоро устареет!

Сначала выясните, как вы собираетесь сохранять уведомления на своем сервере. Я использую Node/Express и MongoDB с Mongoose, и моя схема выглядит так:

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

Обязательно добавьте значок, если вы хотите изменить значок. Я использую один и тот же значок каждый раз, так что мой жестко закодирован в сервисе.

Выяснение правильной веб-службы REST задумалось. GET показался простым выбором, но вызов для получения уведомления вызывает побочные эффекты, поэтому GET отсутствует. Я закончил с POST до /api/notifications с телом {subscriptionId: <SUBSCRIPTION_ID>}. Внутри метода мы в основном выполняем 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);
  });
});

В сервисном работнике мы обязательно должны получить подписку, прежде чем сделать 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);
      });
    })
  );
});

Также стоит отметить, что объект подписки изменился с Chrome 43 на Chrome 45. В Chrome 45 свойство subscriptionId было удалено, просто что-то, на что нужно обратить внимание - этот код был написан для работы с Chrome 43.

Я хотел сделать аутентифицированные вызовы для моего бэкэнда, поэтому мне нужно было выяснить, как получить JWT из моего приложения Angular моему работнику службы. В итоге я использовал postMessage. Вот что я делаю после регистрации сервисного работника:

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

Служащий прослушивает сообщение:

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

Как ни странно, этот слушатель работает в Chrome 43, но не в Chrome 45. Chrome 45 работает с таким обработчиком:

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

В настоящее время push-уведомления занимают довольно много работы, чтобы получить что-то полезное - я действительно с нетерпением жду полезной нагрузки!

Ответ 3

Собственно, полезная нагрузка должна быть реализована в Chrome 50 (дата выхода - 19 апреля 2016 года). В Chrome 50 (и в текущей версии Firefox на рабочем столе) вы можете отправлять произвольные данные вместе с нажатием, чтобы клиент мог избежать дополнительного запроса. Все данные полезной нагрузки должны быть зашифрованы.

Вот данные шифрования от разработчика: https://developers.google.com/web/updates/2016/03/web-push-encryption?hl=en

Ответ 4

Я столкнулся с этой проблемой. Более новые версии firefox и chrome (версия 50+) поддерживают передачу полезной нагрузки.

Dev docs здесь детализирует реализацию того, как это работает. Важно отметить, что google GCM или, возможно, клиент /chome (я не знаю, какой из них) фактически полностью игнорирует полезную нагрузку, если он не зашифрован.

Этот веб-сайт имеет как клиент-серверные реализации, как делать push и retrieve через сервис-работников. Библиотека push, используемая в примерах, представляет собой всего лишь оболочку вокруг обычного вызова REST

сотрудник службы пример реализации:

self.addEventListener('push', function(event) {
var payload = event.data ? event.data.text() : 'no payload';

event.waitUntil(
   self.registration.showNotification('ServiceWorker Cookbook', {
     body: payload,
   })
 );
});

Сервер пример реализации:

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

Пример реализации JavaScript javascript на стороне клиента. Распечатайте необходимые поля.

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