Web Push с VAPID: 400/401 Несанкционированная регистрация

Прежде всего, я уже проверил эти вопросы, без какой-либо удачи:

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

  • Создайте пару ключей VAPID ( с этим руководством).
  • Зарегистрировать сервисного работника (только сервисный работник, я думаю, что manifest.json больше не требуется).
  • Подписаться пользователя на сервер (данные подписки будут храниться в базе данных).
  • Отправьте push-уведомление с помощью webpush gem.

После настройки все работает нормально (на локальном хосте и на удаленной машине). Однако через несколько часов (от 12 до 24 часов) уведомления на удаленной машине перестают работать (локальный хост работает отлично). По истечении этого времени при отправке push-уведомлений со стороны сервера (Rails) появляются следующие ошибки:

  • Хром: UnauthorizedRegistration 400 (без дополнительной информации).
  • Fire Fox: {"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"}

После появления этой ошибки я пытался отписаться и переподписать пользователя при каждом посещении страницы. Поле подписки на БД обновляется после повторной подписки, но ошибка по-прежнему выдается с той же информацией. Никаких ошибок не выдается ни браузеру, ни сервисному работнику.

Я попытался принудительно повторить подписку вручную, поместив код js на консоль Chrome Dev Tools, отменив регистрацию работника службы и сбросив разрешения на push-уведомления, но ничего не решает ошибку. Я могу исправить эту ошибку, только создав новую пару ключей VAPID, перезагрузив удаленный компьютер. После Crebooting машины у меня есть еще 12-24 часа, прежде чем она снова выходит из строя. Кроме того, процесс отправки уведомлений не работает ни на сервере rails (nginx + unicorn), ни на консоли rails, ни на irb.

Я не знаю, куда идти дальше. Хуже того, я могу попробовать исправления только один раз в день, так как они ломаются каждые 24 часа. Я думаю, что мне нужна внешняя помощь с новым взглядом на проблему. Я что-то пропустил? Существует ли какая-либо зависимость от ОС, которую использует VAPID и которую необходимо перезапустить?


Вот некоторые фрагменты кода, которые могут быть полезны. Извините за беспорядок, но я сделал множество изменений, чтобы попытаться заставить его работать.

Регистрация сервисного работника:

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()

Пользовательская подписка и повторная подписка

# 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

Сервисный работник:

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

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

Веб-вызов:

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

2 ответа

Решение

После изменения срока действия с 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
  }
)

Похоже, что библиотека изменилась, вот как я это исправил:

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

Обратите внимание, что ключ истекает, а не истекает, и это время истечения в секундах.

Другие вопросы по тегам