이 Codelab에서는 푸시 알림 서버를 빌드하는 방법을 단계별로 보여줍니다. Codelab을 마치면 다음을 수행하는 서버가 생성됩니다.
- 푸시 알림 구독을 추적합니다 (즉, 클라이언트가 푸시 알림을 선택하면 서버에서 새 데이터베이스 레코드를 만들고 클라이언트가 선택 해제하면 기존 데이터베이스 레코드를 삭제함).
- 단일 클라이언트에 푸시 알림을 전송합니다.
- 구독한 모든 클라이언트에 푸시 알림을 전송합니다.
이 Codelab은 실습을 통해 학습하는 데 중점을 두며 개념에 대해서는 많이 다루지 않습니다. 푸시 알림 개념을 알아보려면 푸시 알림은 어떻게 작동하나요?를 참고하세요.
이 Codelab의 클라이언트 코드는 이미 완료되어 있습니다. 이 Codelab에서는 서버만 구현합니다. 푸시 알림 클라이언트를 구현하는 방법을 알아보려면 Codelab: 푸시 알림 클라이언트 빌드를 확인하세요.
브라우저 호환성
이 Codelab은 다음 운영체제 및 브라우저 조합에서 작동하는 것으로 알려져 있습니다.
- Windows: Chrome, Edge
- macOS: Chrome, Firefox
- Android: Chrome, Firefox
이 Codelab은 다음 운영체제(또는 운영체제와 브라우저 조합)에서 작동하지 않는 것으로 알려져 있습니다.
- macOS: Brave, Edge, Safari
- iOS
애플리케이션 스택
- 서버는 Express.js를 기반으로 빌드됩니다.
- web-push Node.js 라이브러리는 모든 푸시 알림 로직을 처리합니다.
- 구독 데이터는 lowdb를 사용하여 JSON 파일에 작성됩니다.
푸시 알림을 구현하기 위해 이러한 기술을 사용할 필요는 없습니다. 이러한 기술을 선택한 이유는 안정적인 Codelab 환경을 제공하기 때문입니다.
설정
인증 설정
푸시 알림을 작동시키려면 먼저 인증 키를 사용하여 서버와 클라이언트를 설정해야 합니다. 이유는 웹 푸시 프로토콜 요청 서명을 참고하세요.
- 터미널을 엽니다.
- 터미널에서
npx web-push generate-vapid-keys
를 실행합니다. 비공개 키와 공개 키 값을 복사합니다. .env
를 열고VAPID_PUBLIC_KEY
과VAPID_PRIVATE_KEY
를 업데이트합니다.VAPID_SUBJECT
을mailto:test@test.test
로 설정합니다. 이러한 값은 모두 큰따옴표로 묶어야 합니다. 업데이트를 완료하면.env
파일이 다음과 같이 표시됩니다.
VAPID_PUBLIC_KEY="BKiwTvD9HA…"
VAPID_PRIVATE_KEY="4mXG9jBUaU…"
VAPID_SUBJECT="mailto:test@test.test"
public/index.js
를 엽니다.VAPID_PUBLIC_KEY_VALUE_HERE
을 공개 키 값으로 바꿉니다.
구독 관리
클라이언트가 대부분의 구독 프로세스를 처리합니다. 서버에서 해야 하는 주요 작업은 새 푸시 알림 구독을 저장하고 이전 구독을 삭제하는 것입니다. 이러한 구독을 통해 향후 클라이언트에 메시지를 푸시할 수 있습니다. 구독 프로세스에 관한 자세한 내용은 클라이언트를 푸시 알림에 구독을 참고하세요.
새 구독 정보 저장
- 앱 탭에서 서비스 워커 등록을 클릭합니다. 상태 상자에 다음과 유사한 메시지가 표시됩니다.
Service worker registered. Scope: https://example.com
- 앱 탭에서 푸시 구독을 클릭합니다. 브라우저 또는 운영체제에서 웹사이트가 푸시 알림을 보내도록 허용할지 묻는 메시지가 표시될 수 있습니다. 허용 (또는 브라우저/OS에서 사용하는 이에 상응하는 문구)을 클릭합니다. 상태 상자에 다음과 비슷한 메시지가 표시됩니다.
Service worker subscribed to push. Endpoint: https://fcm.googleapis.com/fcm/send/…
- 터미널을 열어 로그를 확인합니다.
/add-subscription
과 함께 일부 데이터가 표시됩니다./add-subscription
는 클라이언트가 푸시 알림을 구독할 때 POST 요청을 보내는 URL입니다. 다음 데이터는 저장해야 하는 클라이언트의 정기 결제 정보입니다. server.js
를 엽니다.- 다음 코드를 사용하여
/add-subscription
경로 핸들러 로직을 업데이트합니다.
app.post('/add-subscription', (request, response) => {
console.log('/add-subscription');
console.log(request.body);
console.log(`Subscribing ${request.body.endpoint}`);
db.get('subscriptions')
.push(request.body)
.write();
response.sendStatus(200);
});
이전 구독 정보 삭제
- 앱 탭으로 돌아갑니다.
- 푸시 알림 수신 거부를 클릭합니다.
- 로그를 다시 확인합니다.
/remove-subscription
다음에 클라이언트의 구독 정보가 표시됩니다. - 다음 코드를 사용하여
/remove-subscription
경로 핸들러 로직을 업데이트합니다.
app.post('/remove-subscription', (request, response) => {
console.log('/remove-subscription');
console.log(request.body);
console.log(`Unsubscribing ${request.body.endpoint}`);
db.get('subscriptions')
.remove({endpoint: request.body.endpoint})
.write();
response.sendStatus(200);
});
알림 보내기
푸시 메시지 보내기에 설명된 대로 서버는 실제로 클라이언트에 직접 푸시 메시지를 보내지 않습니다. 대신 푸시 서비스를 사용하여 이를 수행합니다. 기본적으로 서버는 사용자가 사용하는 브라우저 공급업체가 소유한 웹 서비스 (푸시 서비스)에 웹 서비스 요청 (웹 푸시 프로토콜 요청)을 하여 클라이언트에 메시지를 푸시하는 프로세스를 시작합니다.
- 다음 코드를 사용하여
/notify-me
경로 핸들러 로직을 업데이트합니다.
app.post('/notify-me', (request, response) => {
console.log('/notify-me');
console.log(request.body);
console.log(`Notifying ${request.body.endpoint}`);
const subscription =
db.get('subscriptions').find({endpoint: request.body.endpoint}).value();
sendNotifications([subscription]);
response.sendStatus(200);
});
- 다음 코드를 사용하여
sendNotifications()
함수를 업데이트합니다.
function sendNotifications(subscriptions) {
// TODO
// Create the notification content.
const notification = JSON.stringify({
title: "Hello, Notifications!",
options: {
body: `ID: ${Math.floor(Math.random() * 100)}`
}
});
// Customize how the push service should attempt to deliver the push message.
// And provide authentication information.
const options = {
TTL: 10000,
vapidDetails: vapidDetails
};
// Send a push message to each client specified in the subscriptions array.
subscriptions.forEach(subscription => {
const endpoint = subscription.endpoint;
const id = endpoint.substr((endpoint.length - 8), endpoint.length);
webpush.sendNotification(subscription, notification, options)
.then(result => {
console.log(`Endpoint ID: ${id}`);
console.log(`Result: ${result.statusCode}`);
})
.catch(error => {
console.log(`Endpoint ID: ${id}`);
console.log(`Error: ${error} `);
});
});
}
- 다음 코드를 사용하여
/notify-all
경로 핸들러 로직을 업데이트합니다.
app.post('/notify-all', (request, response) => {
console.log('/notify-all');
response.sendStatus(200);
console.log('Notifying all subscribers');
const subscriptions =
db.get('subscriptions').cloneDeep().value();
if (subscriptions.length > 0) {
sendNotifications(subscriptions);
response.sendStatus(200);
} else {
response.sendStatus(409);
}
});
- 앱 탭으로 돌아갑니다.
- 알림 받기를 클릭합니다. 푸시 알림이 표시됩니다. 제목은
Hello, Notifications!
여야 하고 본문은ID: <ID>
여야 합니다. 여기서<ID>
는 난수입니다. - 다른 브라우저나 기기에서 앱을 열고 푸시 알림을 구독한 다음 모두 알림 버튼을 클릭해 보세요. 구독한 모든 기기에서 동일한 알림을 받아야 합니다 (즉, 푸시 알림 본문의 ID가 동일해야 함).
다음 단계
- 푸시 알림의 작동 방식에 대한 개념을 자세히 알아보려면 푸시 알림 개요를 참고하세요.
- Codelab: 푸시 알림 클라이언트 빌드를 확인하여 알림 권한을 요청하고, 푸시 알림을 수신하도록 기기를 구독하고, 서비스 워커를 사용하여 푸시 메시지를 수신하고 메시지를 알림으로 표시하는 클라이언트를 빌드하는 방법을 알아보세요.