정보실

웹학교

정보실

javascript Vanilla JavaScript로 PWA 구축-2 부 : Push API

본문

이 글은 Web Push API와 cron-schedule을 활용하는 앱을 만드는 3 부로 구성된 시리즈의 두 번째 부분입니다.


https://alligator.io/js/push-api/ 


이 기사에서는 앱의 Web Push API 측면을 다룰 것입니다.


우리는 무엇입니까 


우리는 매일 약을 복용하도록 상기 시켜 주는 간단한 프로그레시브 웹 앱 (PWA)을 만들려고 합니다.


우리 앱에는 Express.js로 구동 되는 웹 서버가 있습니다. 

Express는 푸시 알림을 구독 한 클라이언트에게 알림을 푸시합니다. 또한 프론트 엔드를 제공합니다.


우리가 지금까지 구축 한 것 


지금까지 http : // localhost : 3000에서 정적 파일을 제공하기 위해 설치 가능한 PWA (Progressive Web App) 및 Express.js 서버를 만들었습니다. 

여기에 파트 1로 가서 우리가 어떻게 도착했는지에 대한 모든 것을 읽을 수 있습니다.


푸시 API 작동 방식 


이 부분은 약간 무서울 수 있으므로 간단한 코드 스니펫을 찾고 있다면 건너 뛸 수 있습니다. 

다음은 약간의 연대기입니다 (이 단계를 이 순서대로 수행 할 필요는 없습니다).


사용자에게 알림을 보낼 수 있는 권한을 요청합니다.

브라우저는 서비스 워커를 등록합니다.

브라우저가 Express 서버에서 공개 키를 가져옵니다.

서비스 워커에는 pushManager라는 인터페이스가 있습니다. 

공개 키를 pushManager의 subscribe 함수에 전달하여 새 subscription 객체를 만듭니다.


참고 : 구독 객체에는 푸시 알림이 전송 될 URL 인 엔드 포인트 키가 있습니다. 브라우저만이 이 URL을 생성 할 수 있습니다. 일부 인증 정보도 포함되어 있습니다.


{ "endpoint": "https://fcm.googleapis.com/fcm/send/cyMiHqakiZE:APA91bFUIYbrvtnSGw0dw ...." "expirationTime": null "keys":{ // Receive key "p256dh":"BJG5rNdalnpu6yuRSuly3H221ljDVYRvDk...", // Auth Key "auth": "zG9-yhkAzIdknhMW0d89Aw" } } 


구독 객체를 Express 서버로 보내서 저장합니다.

이제 서버에 키가 있으므로 서버의 개인 키 (3 단계의 공개 키와 일치하는 키)를 사용하여 매우 흥미로운 암호화 마법을 수행합니다. 그런 다음 암호화 된 메시지를 엔드 포인트로 보냅니다.


암호화 프로세스에 대한 자세한 내용을 보려면 이 MDN 기사에서 암호화 프로세스를 읽어 보는 것이 좋습니다.


푸시 서버 (Apple, Mozilla, Google 등에서 관리)는 요청을 분석하고 유효한 경우 푸시 알림을 응용 프로그램에 보냅니다.


서비스 담당자는 '푸시'이벤트 리스너에서 알림을 받습니다. 그리고 우리는 그 정보로 원하는 것을 할 수 있습니다.


마침내 www. 이것이 이 기사의 목적을 위해 알아야 할 전부입니다. 지금 코딩하자!


Javascript에서 푸시 알림 구독 


고객을 구독하는 방법은 다음과 같습니다.


(async () => { if('serviceWorker' in navigator) { // We first get the registration const registration = await navigator.serviceWorker.ready; // Asking for the subscription object let subscription = await registration.pushManager.getSubscription(); // If we don't have a subscription we have to create and register it! if (!subscription) { subscription = await subscribe(registration); } // Implementing an unsubscribe button document.getElementById('unsubscribe').onclick = () => unsubscribe(); } })() // We use this function to subscribe to our push notifications // As soon as you run this code once, it shouldn't run again if the initial subscription went well // Except if you clear your storage const subscribe = async (registration) => { // First get a public key from our Express server const response = await fetch('/vapid-public-key'); const body = await response.json(); const publicKey = body.publicKey; // this is an annoying part of the process we have to turn our public key // into a Uint8Array const Uint8ArrayPublicKey = urlBase64ToUint8Array(publicKey); // registering a new subscription to our service worker's Push manager const subscription = await registration.pushManager.subscribe({ // don't worry about the userVisible only atm userVisibleOnly: true, applicationServerKey: Uint8ArrayPublicKey }); // Sending the subscription object to our Express server await fetch('/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(subscription.toJSON()) } ); return subscription; }; // Let's create an unsubscribe function as well const unsubscribe = async () => { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); // This tells our browser that we want to unsubscribe await subscription.unsubscribe(); // This tells our Express server that we want to unsubscribe await fetch("/unsubscribe", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(subscription.toJSON()) }); writeSubscriptionStatus("Unsubscribed"); }; // This simply shows our user that they are unsubscribed const writeSubscriptionStatus = subscriptionStatus => { document.getElementById("status").innerHTML = subscriptionStatus; }; // I have found this code (or variations of) from; multiple sources // but I could not find the original author // here's one such source: // https://stackoverflow.com/questions/42362235/web-pushnotification-unauthorizedregistration-or-gone-or-unauthorized-sub const urlBase64ToUint8Array = (base64String) => { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; }; 


Express 서버에서 푸시 알림 설정 


우리 서버에는 복잡한 암호화가 많이 있습니다. 그래서 우리는 우리를 위해 그것을 관리하기 위해 web-push라는 라이브러리를 사용할 것입니다.


$ npm install --save web-push # or: $ yarn add web-push 


// ... See previous article for the rest of the code const bodyParser = require('body-parser'); const webPush = require('web-push'); // for this application we use allSubscription object to manage our subscriptions // this is NOT GOOD for production since it makes our application stateful const allSubscriptions = {}; // We use webpush to generate our public and private keys const { publicKey, privateKey } = webPush.generateVAPIDKeys(); // We are giving webpush the required information to encrypt our data webPush.setVapidDetails( 'https://jmisteli.com', publicKey, privateKey ); // bodyParse.json() allows us to easily read json bodies app.use(bodyParser.json()); // Send our public key to the client app.get('/vapid-public-key', (req, res) => res.send({ publicKey })); // Allows our client to subscribe app.post('/subscribe', (req, res) => { const subscription = req.body; registerTasks(subscription); res.send('subscribed!'); }); const registerTasks = (subscription) => { const endpoint = subscription.endpoint; // the endpoints are the keys of our subscriptions object // Every 3 seconds we will send a notification with the message 'hey this is a push!' const intervalID = setInterval(()=>{ sendNotification(subscription, 'Hey this is a push!') }, 3000); allSubscriptions[endpoint] = intervalID; } // Allows our client to unsubscribe app.post('/unsubscribe', (req, res) => { const endpoint = req.body.endpoint; // We find the client's endpoint and clear the interval associated with it const intervalID = allSubscriptions[endpoint]; clearInterval(intervalID); // We delete the key delete allSubscriptions[endpoint]; }); // This function takes a subscription object and a payload as an argument // It will try to encrypt the payload // then attempt to send a notification via the subscription's endpoint const sendNotification = async (subscription, payload) => { // This means we won't resend a notification if the client is offline const options = { TTL: 0 }; if (!subscription.keys) { payload = payload || null; } // web-push's sendNotification function does all the work for us try { const res = await webPush.sendNotification(subscription, payload, options); console.log(res, 'sent!'); } catch (e) { console.log('error sending', e); } } 


푸시 알림 서비스 작업자 


마지막으로 고객 서비스 직원에게도 푸시를 듣는 방법은 다음과 같습니다.


self.addEventListener('push', function (e) { const message = e.data; // The notificationOptions will shape the look and behavior of our notification const notificationOptions = { body: `Time is the message: ${message}`, // we use the images from the PWA generator we made icon: '/images/icons/icon-512x512.png', vibrate: [100, 50, 100], data: { dateOfArrival: Date.now(), primaryKey: '2' }, actions: [ { action: 'close', title: 'Close' } ] }; e.waitUntil( // We use the service worker's registration `showNotification` function to display the Notification self.registration.showNotification('💊💊 You got notified! 💊💊', notificationOptions) ); }); 


알림 API 작동 방식에 대한 자세한 내용은 웹 알림 API를 사용하여 기본 기능을 확인하십시오.



페이지 정보

조회 91회 ]  작성일20-03-01 14:54

웹학교