提问人:Mark Tyers 提问时间:11/2/2023 更新时间:11/2/2023 访问量:47
使用 Deno 进行 Web 推送
Web Push with Deno
问:
我正在构建一个简单的概念证明,尝试使用 Deno 启用网络推送。似乎没有任何作为 Deno 模块的原生实现,所以我一直在使用 NodeJS 库。这是基于一篇 Medium 文章
我运行了以下命令来生成密钥:
$ deno run --allow-read npm:[email protected] generate-vapid-keys
经过大量修补,我得到了一些代码,但它在发送通知时抛出错误:
error: Uncaught (in promise) TypeError: Invalid RSA private key
at SignImpl.sign (ext:deno_node/internal/crypto/sig.ts:48:33)
at sign (file:///home/codio/.cache/deno/npm/registry.npmjs.org/jwa/2.0.0/index.js:152:45)
at Object.sign (file:///home/codio/.cache/deno/npm/registry.npmjs.org/jwa/2.0.0/index.js:200:27)
at Object.jwsSign [as sign] (file:///home/codio/.cache/deno/npm/registry.npmjs.org/jws/4.0.0/lib/sign-stream.js:32:24)
at Object.getVapidHeaders (file:///home/codio/.cache/deno/npm/registry.npmjs.org/web-push/3.6.6/src/vapid-helper.js:226:19)
at WebPushLib.generateRequestDetails (file:///home/codio/.cache/deno/npm/registry.npmjs.org/web-push/3.6.6/src/web-push-lib.js:278:40)
at WebPushLib.sendNotification (file:///home/codio/.cache/deno/npm/registry.npmjs.org/web-push/3.6.6/src/web-push-lib.js:341:29)
at file:///home/codio/workspace/app.js:37:13
at Layer.handle [as handle_request] (file:///home/codio/.cache/deno/npm/registry.npmjs.org/express/4.18.2/lib/router/layer.js:95:5)
at next (file:///home/codio/.cache/deno/npm/registry.npmjs.org/express/4.18.2/lib/router/route.js:144:13)
代码如下
import_map.json
{
"imports": {
"express": "npm:[email protected]",
"web-push": "npm:[email protected]",
"cors": "npm:[email protected]"
}
}
// app.js
import express from 'express'
const app = express()
import webpush from 'web-push'
import cors from 'cors'
const port = 8080
app.use(cors())
app.use(express.json())
app.use(express.static('public'))
const subDatabse = []
const apiKeys = {
pubKey: 'BMmS-0NgSh8tRe0JBMKuVbeAYUQDju4m5jaQaVV4XuuH59ySZttn_SqlWnLO2lw4o7pDo7A0dMYRRbu9Rr59zFY',
privKey: 'ERZAl-oGmLZRur-wIyRO-1WM2dNSlipINkX71q9oUwQ'
}
webpush.setVapidDetails('mailto:[email protected]', apiKeys.pubKey, apiKeys.privKey)
app.get('/', (req, res) => res.send('Hello world'))
app.post('/save-subscription', (req, res) => {
subDatabse.push(req.body)
console.log(subDatabse)
res.json({ status: 'Success', message: 'Subscription saved!' })
})
app.get('/send-notification', (req, res) => {
console.log('send-notification')
if (subDatabse.length === 0) throw new Error('no subscriptions')
console.log(subDatabse[0])
webpush.sendNotification(subDatabse[0], 'Hello world')
res.json({ 'statue': 'Success', 'message': 'Message sent to push service' })
})
app.listen(port, () => {
console.log(`Server running on port ${port}`)
})
<!DOCTYPE html>
<html>
<head>
<script src="script.js" defer></script>
</head>
<body>
<button onclick="main()">Enable notification</button>
<button id="register">Register</button>
</body>
</html>
// script.js
const checkPermission = () => {
if (!('serviceWorker' in navigator)) throw new Error("No support for service worker!")
if (!('Notification' in window)) throw new Error("No support for notification API")
if (!('PushManager' in window)) throw new Error("No support for Push API")
}
const registerSW = async () => {
console.log('registerSW')
const registration = await navigator.serviceWorker.register('sw.js')
return registration
}
const requestNotificationPermission = async () => {
const permission = await Notification.requestPermission();
if (permission !== 'granted') throw new Error('Notification permission not granted')
}
const main = async () => {
console.log('enabling notifications')
checkPermission()
await requestNotificationPermission()
await registerSW()
}
navigator.serviceWorker.ready.then((registration) => {
document.querySelector('button#register').addEventListener('click', event => {
navigator.serviceWorker.ready.then( registration => {
registration.active.postMessage({ type: 'subscribe' })
})
})
})
// sw.js
const serverPort = 8080
const urlBase64ToUint8Array = base64String => {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
const rawData = atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) outputArray[i] = rawData.charCodeAt(i)
return outputArray;
}
const saveSubscription = async subscription => {
const response = await fetch(`https://roundtower-iconricardo-8080.codio-box.uk/save-subscription`, {
method: 'post',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify(subscription)
})
return response.json()
}
self.addEventListener('install', async event => {
self.skipWaiting()
})
self.addEventListener('activate', event => console.log('activate'))
self.addEventListener('message', async event => {
if (event.data && event.data.type === 'subscribe') {
console.log('subscribe message')
const subscription = await self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('BMmS-0NgSh8tRe0JBMKuVbeAYUQDju4m5jaQaVV4XuuH59ySZttn_SqlWnLO2lw4o7pDo7A0dMYRRbu9Rr59zFY')
})
const response = await saveSubscription(subscription)
console.log(response)
}
})
self.addEventListener('push', event => {
self.registration.showNotification('Wohoo!!', { body: event.data.text() })
})
答: 暂无答案
评论
authorized_keys id_rsa id_rsa.pub