Codelab: 푸시 알림 서버 빌드

Kate Jeffreys
Kate Jeffreys

이 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. 사이트를 미리 보려면 앱 보기를 누른 다음 전체 화면전체 화면을 누릅니다.
  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. 도구를 클릭한 다음 로그를 클릭하여 Glitch 로그를 엽니다. /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. Glitch 로그를 다시 확인합니다. /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: 푸시 알림 클라이언트 빌드에서 알림 권한을 요청하고, 푸시 알림을 수신하기 위해 기기를 구독하고, 서비스 워커를 사용하여 푸시 메시지를 수신하고 메시지를 알림으로 표시하는 클라이언트를 빌드하는 방법을 알아보세요.