7

First of all, I've already check these questions, without any luck:

I am trying to implement web push notifications for a web app that I'm working on. Currently, I've achieved the following goals:

  • Create a VAPID keys pair (with this guide).
  • Register a service worker (only a service worker, I think that manifest.json is no longer required).
  • Subscribe the user to the server (subscription data will be stored in the database).
  • Send a push notification with webpush gem.

After setting it up, everything works fine (on localhost and on a remote machine). However, after some hours (between 12 and 24 hours), the notifications stop working on the remote machine (localhost works perfectly). After that time, the following errors are thrown when sending the push notifications from the server side (Rails):

  • Chrome: UnauthorizedRegistration 400 (no extra info).
  • Firefox: {"code": 401, "errno": 109, "error": "Unauthorized", "more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes", "message": "Request did not validate Invalid bearer token: Auth > 24 hours in the future"}

After this error appeared, I tried to unsubscribe and resubscribe the user on every page visit. The subscription field on the db is updated after the resubscription is done, but the error is still being thrown, with the same information. No errors are thrown on the browser, nor service worker.

I've tried to force the resubscription manually by placing some js code on the Chrome Dev Tools console, unregistering the service worker, and reseting the push notification permissions, but nothing solves the error. I can only fix this error by creating a new VAPID key pair rebooting the remote machine. After crebooting the machine, I've another 12-24 hours before it fails again. Also, the notifications send process don't work neither on rails server (nginx + unicorn), rails console, nor irb.

I don't know where to go from now. Even worst, I can only try fixes once a day, since it'll break every 24 hours. I think I need some external help with a fresh vision of the problem. Am I missing something? Is there any OS dependency that VAPID uses and needs to be restarted?


Here are some code snippets that may be useful. Sorry for the mess, but I've done tons of modifications to try making it work.

Service worker registration:

serviceWorkerRegistration = null

registerServiceWorker = ->
  if 'serviceWorker' of navigator && 'PushManager' of window
    navigator.serviceWorker.register("<js url>").then (reg) ->
      serviceWorkerRegistration = reg
      checkSubscription()

    .catch (error) ->
      console.warn 'Service Worker Error', error

  else
    console.warn 'Push messaging is not supported'

registerServiceWorker()

User subscription and resubscription

# Refresh user subscription (unsub + sub)
refreshUserSubscription = ->
  unsubscribeUser(subscribeUser)

# Subscribe the user to the push server
subscribeUser = ->
  return if !serviceWorkerRegistration

  # Subscribe
  serviceWorkerRegistration.pushManager.subscribe
    userVisibleOnly: true
    applicationServerKey: urlB64ToUint8Array('...')

  .then (subscription) ->
    pushSubscription subscription

  .catch (err) ->
    console.warn 'Failed to subscribe the user: ', err

# Unsubscribe user
unsubscribeUser = (callback)->
  return unless serviceWorkerRegistration

  serviceWorkerRegistration.pushManager.getSubscription().then (subscription) ->
    if subscription
      subscription.unsubscribe().then(callback)
    else
      callback()
  .catch (error) ->
    console.warn 'Error unsubscribing', error

# Push subscription to the web app
pushSubscription = (subscription) ->
  data = if subscription then subscription.toJSON() else {}
  $.post "<back-end endpoint>", subscription: data

# Fetch current subscription, and push it.
checkSubscription = () ->
  serviceWorkerRegistration.pushManager.getSubscription()
    .then (subscription) ->
      pushSubscription(subscription)

# I think that this should be done with promises instead of a simple timeout.
setTimeout refreshUserSubscription, 1000

Service worker:

self.addEventListener 'push', (event) ->
  title = "Example"
  options = { body: "Example" }

  notificationPromise = self.registration.showNotification(title, options)
  event.waitUntil(notificationPromise)

Web push call:

webpush = WebPush.new({ endpoint: '...', keys: { p256dh: '...', auth: '...' } })
webpush.set_vapid_details(
  "mailto:#{CONTACT_EMAIL}",
  "<base64 public key>",
  "<base64 private key>"
)
webpush.send_notification("foo")
4

2 回答 2

1

看起来图书馆已经改变了,这就是我修复它的方式:

def send_push(payload, endpoint, p256dh, auth)
  Webpush.payload_send(
    message: payload,
    endpoint: endpoint,
    p256dh: p256dh,
    auth: auth,
    vapid: {
      public_key: '...',
      private_key: '...',
      expiration: 12 * 60 * 60
    }
  )
end

请注意,密钥是过期而不是 exp,它是以秒为单位的过期时间。

于 2017-11-08T22:18:19.140 回答
1

将过期时间从 24 小时(默认)更改为 12 小时后,它现在可以正常工作了:

Webpush.payload_send(
  message: "Hi!",
  endpoint: "...",
  p256dh: "...",
  auth: "...",
  vapid: {
    subject: "...",
    public_key: ENV['VAPID_PUBLIC_KEY'],
    private_key: ENV['VAPID_PRIVATE_KEY'],
    exp: 12.hours
  }
)
于 2017-05-04T09:48:12.540 回答