Codelab: 푸시 알림 서버 빌드

케이트 제프리스
케이트 제프리스
케이스 바스크
케이스 바스크

이 Codelab에서는 푸시 알림 서버를 빌드하는 방법을 단계별로 보여줍니다. Codelab을 마치면 다음을 수행하는 서버를 갖추게 됩니다.

  • 푸시 알림 구독을 추적합니다.즉, 클라이언트가 푸시 알림을 선택하면 서버에서 새 데이터베이스 레코드를 만들고 클라이언트가 선택 해제하면 기존 데이터베이스 레코드를 삭제합니다.
  • 단일 클라이언트에 푸시 알림을 전송합니다.
  • 구독한 모든 클라이언트에 푸시 알림을 전송합니다.

이 Codelab에서는 실습을 통해 학습하는 데 중점을 두고 있으며 개념에 관해서는 다루지 않습니다. 푸시 알림 개념에 대해 알아보려면 푸시 알림의 작동 원리를 확인하세요.

이 Codelab의 클라이언트 코드는 이미 완성되어 있습니다. 이 Codelab에서는 서버만 구현합니다. 푸시 알림 클라이언트를 구현하는 방법은 Codelab: 푸시 알림 클라이언트 빌드를 참고하세요.

전체 코드는 push-notifications-server-codelab-complete(소스)를 참고하세요.

브라우저 호환성

이 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 환경을 제공하기 때문에 이 기술을 선택했습니다.

설정

수정 가능한 코드 사본 받기

이 안내의 오른쪽에 표시되는 코드 편집기는 이 Codelab 전체에서 Glitch UI라고 합니다.

  1. 리믹스하여 수정을 클릭하여 프로젝트를 수정할 수 있도록 합니다.

인증 설정

푸시 알림이 작동하도록 하려면 먼저 인증 키로 서버와 클라이언트를 설정해야 합니다. 이유는 웹 푸시 프로토콜 요청 서명을 참조하세요.

  1. 도구터미널을 차례로 클릭하여 Glitch 터미널을 엽니다.
  2. 터미널에서 npx web-push generate-vapid-keys를 실행합니다. 비공개 키와 공개 키 값을 복사합니다.
  3. .env를 열고 VAPID_PUBLIC_KEYVAPID_PRIVATE_KEY를 업데이트합니다. VAPID_SUBJECTmailto:test@test.test로 설정합니다. 이러한 값은 모두 큰따옴표로 묶어야 합니다. 업데이트 후에는 .env 파일이 다음과 같이 표시됩니다.
VAPID_PUBLIC_KEY="BKiwTvD9HA…"
VAPID_PRIVATE_KEY="4mXG9jBUaU…"
VAPID_SUBJECT="mailto:test@test.test"
  1. Glitch 터미널을 닫습니다.
  1. public/index.js를 엽니다.
  2. VAPID_PUBLIC_KEY_VALUE_HERE를 공개 키 값으로 바꿉니다.

구독 관리

가입 절차의 대부분은 클라이언트가 처리합니다. 서버에서 해야 하는 주요 작업은 새 푸시 알림 구독을 저장하고 이전 구독을 삭제하는 것입니다. 이러한 구독을 통해 향후 클라이언트에 메시지를 푸시할 수 있습니다. 구독 프로세스에 관한 자세한 내용은 클라이언트의 푸시 알림 구독을 참고하세요.

새 구독 정보 저장

  1. 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.
  1. 앱 탭에서 서비스 워커 등록을 클릭합니다. 상태 상자에 다음과 비슷한 메시지가 표시됩니다.
Service worker registered. Scope: https://desert-cactus-sunset.glitch.me/
  1. 앱 탭에서 푸시 구독을 클릭합니다. 브라우저나 운영체제에서 웹사이트에서 푸시 알림을 보낼 수 있는지 묻는 메시지가 표시될 것입니다. 허용 (또는 브라우저/OS에서 사용하는 동일한 문구)을 클릭합니다. 상태 상자에 다음과 비슷한 메시지가 표시됩니다.
Service worker subscribed to push.  Endpoint: https://fcm.googleapis.com/fcm/send/…
  1. Glitch UI에서 소스 보기를 클릭하여 코드로 돌아갑니다.
  2. 도구를 클릭한 다음 로그를 클릭하여 글리치 로그를 엽니다. /add-subscription가 표시된 후에 몇 가지 데이터가 표시됩니다. /add-subscription는 클라이언트가 푸시 알림을 구독하려고 할 때 POST 요청을 보내는 URL입니다. 이어지는 데이터는 저장해야 하는 클라이언트의 정기 결제 정보입니다.
  3. server.js를 엽니다.
  4. 다음 코드를 사용하여 /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);
});

이전 구독 정보 삭제

  1. 앱 탭으로 돌아갑니다.
  2. 푸시 구독 취소를 클릭합니다.
  3. 글리치 로그를 다시 살펴보세요. /remove-subscription가 표시되고 그 뒤에 클라이언트의 정기 결제 정보가 표시됩니다.
  4. 다음 코드를 사용하여 /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);
});

알림 보내기

푸시 메시지 보내기에서 설명한 것처럼 서버는 실제로 클라이언트에 직접 푸시 메시지를 보내지 않습니다. 오히려 이를 수행하기 위해 푸시 서비스를 사용합니다. 서버는 기본적으로 사용자가 사용하는 브라우저 공급업체가 소유한 웹 서비스 (푸시 서비스)에 웹 서비스 요청 (웹 푸시 프로토콜 요청)을 전송하여 클라이언트에 메시지를 푸시하는 프로세스를 시작합니다.

  1. 다음 코드를 사용하여 /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);
});
  1. 다음 코드를 사용하여 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} `);
      });
  });
}
  1. 다음 코드를 사용하여 /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);
  }
});
  1. 앱 탭으로 돌아갑니다.
  2. 푸시 구독 취소를 클릭한 다음 푸시 구독을 다시 클릭합니다. 앞서 언급했듯이 코드를 수정할 때마다 Glitch에서 프로젝트를 다시 시작하고 시작 시 데이터베이스를 삭제하도록 프로젝트가 구성되기 때문에 이것만 필요합니다.
  3. 알림 받기를 클릭합니다. 푸시 알림을 받게 됩니다. 제목은 Hello, Notifications!이고 본문은 ID: <ID>이어야 합니다. 여기서 <ID>는 랜덤 숫자입니다.
  4. 다른 브라우저나 기기에서 앱을 열고 푸시 알림을 구독한 후 모두 알림 버튼을 클릭합니다. 구독 중인 모든 기기에서 동일한 알림을 받게 됩니다. 즉, 푸시 알림 본문의 ID가 동일해야 합니다.

다음 단계

  • 푸시 알림의 작동 방식에 대한 개념적 이해는 푸시 알림 개요를 참조하세요.
  • Codelab: 푸시 알림 클라이언트 빌드를 참고하여 알림 권한을 요청하고, 기기를 구독하여 푸시 알림을 수신하며, 서비스 워커를 사용하여 푸시 메시지를 수신하고 메시지를 알림으로 표시하는 클라이언트를 빌드하는 방법을 알아보세요.