使用VAPID进行Web Push:400/401未经授权的注册

7
首先,我已经检查了这些问题,但没有任何运气:
我正在尝试为我正在开发的 Web 应用程序实现 Web 推送通知。目前,我已经实现了以下目标:
  • 创建 VAPID 密钥对(使用此指南)。
  • 注册服务工作者(仅服务工作者,我认为不再需要 manifest.json)。
  • 订阅用户到服务器(订阅数据将存储在数据库中)。
  • 使用 webpush gem 发送推送通知。

设置后,一切正常运行(本地和远程机器)。然而,在若干小时后(12到24小时之间),远程机器上的通知停止工作(本地主机正常运行)。这段时间过后,从服务器端(Rails)发送推送通知时会抛出以下错误:

  • Chrome: UnauthorizedRegistration 400(没有额外信息)。
  • 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"}

出现此错误后,我尝试在每次页面访问时取消订阅并重新订阅用户。重新订阅完成后,更新了数据库中的订阅字段,但仍会抛出相同的错误信息。浏览器和服务工作者都没有抛出任何错误。

我尝试通过在Chrome Dev Tools控制台中放置一些js代码,注销服务工作者并重置推送通知权限来手动强制重新订阅,但是没有什么可以解决这个错误。我只能通过创建新的VAPID密钥对重新启动远程机器来解决此错误。在重新启动机器之后,我还有12-24小时才会再次失败。另外,通知发送过程在rails server(nginx + unicorn)rails consoleirb上都无法工作。

我不知道接下来该怎么办。更糟糕的是,由于它每24小时就会崩溃,我只能每天尝试修复一次。我认为我需要一些外部帮助来提供新的问题视角。我是否遗漏了什么?是否有任何VAPID使用并需要重新启动的操作系统依赖项?


这里有一些可能有用的代码片段,涉及编程相关内容。抱歉这些代码有点凌乱,因为我进行了很多修改来尝试使它们正常工作。
Service Worker注册:
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)

Web推送调用:

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个回答

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

注意,关键字是expiration而不是exp,它表示过期时间(以秒为单位)。

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

嗨,我正在尝试实现类似的东西(https://stackoverflow.com/questions/50361320/service-worker-push-notification-with-vapid-prv-pub-keys)。我不明白的一点是,我是否需要刷新浏览器订阅注册,还是一旦浏览器允许通知并发送订阅,就可以无限发送通知了?大约24小时后,我收到401 NotRegistered的错误提示。 - CLod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接