首先,我已经检查了这些问题,但没有任何运气:
创建新的VAPID密钥对重新启动远程机器来解决此错误。在重新启动机器之后,我还有12-24小时才会再次失败。另外,通知发送过程在rails server(nginx + unicorn)、rails console和irb上都无法工作。
这里有一些可能有用的代码片段,涉及编程相关内容。抱歉这些代码有点凌乱,因为我进行了很多修改来尝试使它们正常工作。
Service Worker注册:
- Web Push API Chrome, 返回 "Unauthorized Registration"
- [WebPush][VAPID] 请求失败,返回 400 UnauthorizedRegistration
- 创建 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代码,注销服务工作者并重置推送通知权限来手动强制重新订阅,但是没有什么可以解决这个错误。我只能通过我不知道接下来该怎么办。更糟糕的是,由于它每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")