Web Push с VAPID: 400/401 Несанкционированная регистрация
Прежде всего, я уже проверил эти вопросы, без какой-либо удачи:
- Web Push API Chrome, возвращающий "Несанкционированную регистрацию"
- [WebPush] [VAPID] Запрос не выполняется с 400 UnauthorizedRegistration
Я пытаюсь реализовать 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
Обратите внимание, что ключ истекает, а не истекает, и это время истечения в секундах.