Прежде всего, я уже безуспешно проверял эти вопросы:
- API Chrome, возвращающий неавторизованную регистрацию
- Запрос [WebPush][VAPID] завершается с ошибкой 400 UnauthorizedRegistration
Я пытаюсь реализовать веб-push-уведомления для веб-приложения, над которым я работаю. На данный момент я достиг следующих целей:
- Создайте пару ключей VAPID (с помощью этого руководства. а>).
- Зарегистрируйте сервис-воркер (только сервис-воркер, думаю, что
manifest.json
уже не требуется). - Подпишите пользователя на сервер (данные о подписке будут храниться в базе данных).
- Отправьте push-уведомление с помощью гема webpush.
После настройки все работает нормально (на локальном хосте и на удаленной машине). Однако через несколько часов (от 12 до 24 часов) уведомления перестают работать на удаленной машине (localhost работает отлично). По истечении этого времени при отправке push-уведомлений со стороны сервера (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"}
После появления этой ошибки я пытался отписаться и переподписать пользователя при каждом посещении страницы. Поле подписки в базе данных обновляется после повторной подписки, но ошибка все еще возникает с той же информацией. Никаких ошибок ни в браузере, ни в сервис-воркере не выдается.
Я попытался принудительно выполнить повторную подписку вручную, поместив некоторый код js в консоль Chrome Dev Tools, отменив регистрацию работника службы и сбросив разрешения на push-уведомления, но ничто не устраняет ошибку. Я могу исправить эту ошибку, только создав новую пару ключей VAPID, перезагрузив удаленную машину. После создания машины у меня есть еще 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")