웹 푸시 라이브러리를 사용하여 메시지 전송

웹 푸시로 작업할 때 고충 중 하나는 푸시 메시지를 트리거하는 것이 '까다로'입니다. 푸시 메시지를 트리거하려면 애플리케이션이 푸시에 POST 요청을 해야 함 웹 푸시 후 웹 푸시에 따라 프로토콜을 사용합니다. 모든 제품에 푸시를 사용하려면 VAPID를 사용해야 하는 브라우저 (애플리케이션 서버 키라고도 함). 이는 기본적으로 메시지를 보낼 수 있습니다 푸시 메시지로 데이터를 전송하려면 데이터가 암호화된 특정 헤더 를 추가해야 브라우저가 메시지를 올바르게 복호화할 수 있습니다.

푸시 트리거의 주요 문제는 문제가 발생하면 진단이 어렵고 있습니다. 시간이 지남에 따라 더 많은 브라우저가 지원되면서 개선되고 있지만 쉽지 않은 일입니다. 대상 라이브러리를 사용하여 암호화, 서식 지정 및 중요한 역할을 합니다

라이브러리가 하는 일에 대해 자세히 알아보고 싶다면 다음 섹션에서 살펴보겠습니다. 지금은 구독을 관리하고 기존 웹 푸시 라이브러리를 사용하여 푸시 요청을 할 수 있습니다.

이 섹션에서는 web-push 노드 라이브러리를 사용하여 v3 지도에 통합할 수 있습니다. 다른 언어에도 차이가 있지만 그렇게 다르지 않을 것입니다. Node는 JavaScript이고 가장 편한 방법이라는 것을 깨달았습니다.

단계는 다음과 같습니다.

  1. 백엔드로 구독을 전송하고 저장합니다.
  2. 저장된 구독을 검색하고 푸시 메시지를 트리거합니다.

구독 저장 중

데이터베이스에서 PushSubscription를 저장하고 쿼리하는 방법은 다음에 따라 다릅니다. 서버 측 언어와 데이터베이스를 선택하게 되지만, 예시가 있었습니다.

데모 웹페이지에서는 간단한 POST 요청을 실행하여 PushSubscription가 백엔드로 전송됩니다.

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

데모의 Express 서버에는 /api/save-subscription/ 엔드포인트:

app.post('/api/save-subscription/', function (req, res) {

이 경로에서는 요청이 양호하며 가비지:

const isValidSaveRequest = (req, res) => {
  // Check the request body has at least an endpoint.
  if (!req.body || !req.body.endpoint) {
    // Not a valid subscription.
    res.status(400);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'no-endpoint',
          message: 'Subscription must have an endpoint.',
        },
      }),
    );
    return false;
  }
  return true;
};

구독이 유효하면 구독을 저장하고 적절한 JSON 응답:

return saveSubscriptionToDatabase(req.body)
  .then(function (subscriptionId) {
    res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({data: {success: true}}));
  })
  .catch(function (err) {
    res.status(500);
    res.setHeader('Content-Type', 'application/json');
    res.send(
      JSON.stringify({
        error: {
          id: 'unable-to-save-subscription',
          message:
            'The subscription was received but we were unable to save it to our database.',
        },
      }),
    );
  });

이 데모는 nedb를 사용하여 구독을 저장합니다. 간단한 파일 기반 데이터베이스이지만 원하는 데이터베이스를 사용할 수 있습니다. 우리는 이것을 단지 별도의 설정이 필요하지 않습니다. 프로덕션의 경우 보다 안정적인 것을 사용해야 합니다. 저는 오래된 MySQL을 사용하세요.)

function saveSubscriptionToDatabase(subscription) {
  return new Promise(function (resolve, reject) {
    db.insert(subscription, function (err, newDoc) {
      if (err) {
        reject(err);
        return;
      }

      resolve(newDoc._id);
    });
  });
}

푸시 메시지 보내기

푸시 메시지를 보낼 때는 궁극적으로 메시지를 보낼 수 있습니다. 일반적인 방법은 관리자가 액세스할 수 있는 관리 페이지를 만드는 것입니다. 푸시 메시지를 구성하고 트리거합니다. 하지만 로컬에서 실행하거나 PushSubscription 목록에 액세스하고 코드를 실행하여 푸시 메시지를 트리거합니다.

데모에는 '관리자 추천'이 푸시를 트리거할 수 있는 페이지가 있습니다. 데모일 뿐이므로 공개 페이지로 이동합니다.

데모 작동과 관련된 각 단계를 살펴보겠습니다. 베이비 모든 사람이 따라야 하는 단계를 수행해야 합니다.

사용자 구독에 관해 설명할 때 applicationServerKey를 옵션 subscribe()개. 이 비공개 키는 백엔드에서 필요합니다.

데모에서는 이러한 값이 Node 앱에 이렇게 추가됩니다 (코드는 지루하지만 마법은 없다는 것을 알아두세요.)

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

다음으로 노드 서버의 web-push 모듈을 설치해야 합니다.

npm install web-push --save

그런 다음 Node 스크립트에 web-push 모듈이 필요합니다. 다음과 같습니다.

const webpush = require('web-push');

이제 web-push 모듈을 사용할 수 있습니다. 먼저 web-push 모듈에 다음 정보를 제공해야 합니다. 애플리케이션 서버 키를 사용합니다 VAPID 키라고도 하는 참조하세요.)

const vapidKeys = {
  publicKey:
    'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
  privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};

webpush.setVapidDetails(
  'mailto:web-push-book@gauntface.com',
  vapidKeys.publicKey,
  vapidKeys.privateKey,
);

'mailto:' 문자열. 이 문자열은 URL 또는 mailto여야 합니다. 이메일 주소를 입력하세요. 이 정보는 실제로 웹 푸시 서비스에 푸시를 트리거합니다 이렇게 하는 이유는 웹 푸시 서비스에 몇 가지 정보를 확보하여 발신자에게 연락할 수 있습니다.

이제 web-push 모듈을 사용할 준비가 되었습니다. 다음 단계는 푸시 메시지를 트리거하는 것입니다.

데모에서는 역할 관리 패널을 사용하여 푸시 메시지를 트리거합니다.

관리 페이지의 스크린샷

'푸시 메시지 트리거' 클릭 버튼을 누르면 /api/trigger-push-msg/에 POST 요청이 전송됩니다. 푸시 메시지를 보내라는 신호이므로 백엔드에서 익스프레스를 사용할 수 있습니다

app.post('/api/trigger-push-msg/', function (req, res) {

이 요청이 수신되면 데이터베이스에서 구독을 가져와 각각에 대해 푸시 메시지를 트리거합니다.

return getSubscriptionsFromDatabase().then(function (subscriptions) {
  let promiseChain = Promise.resolve();

  for (let i = 0; i < subscriptions.length; i++) {
    const subscription = subscriptions[i];
    promiseChain = promiseChain.then(() => {
      return triggerPushMsg(subscription, dataToSend);
    });
  }

  return promiseChain;
});

그러면 triggerPushMsg() 함수는 web-push 라이브러리를 사용하여 제공합니다.

const triggerPushMsg = function (subscription, dataToSend) {
  return webpush.sendNotification(subscription, dataToSend).catch((err) => {
    if (err.statusCode === 404 || err.statusCode === 410) {
      console.log('Subscription has expired or is no longer valid: ', err);
      return deleteSubscriptionFromDatabase(subscription._id);
    } else {
      throw err;
    }
  });
};

webpush.sendNotification()를 호출하면 프로미스가 반환됩니다. 만약 성공적으로 전송된 후에 프라미스가 해결되고 별다른 조치를 취하지 않아도 됩니다 프라미스가 거부되면 PushSubscription가 여전히 사용 중인지 알려줍니다. 여부를 지정합니다.

푸시 서비스의 오류 유형을 확인하려면 상태 코드를 확인하는 것이 가장 좋습니다. 오류 푸시 서비스에 따라 메시지가 다르며 어떤 것이 다른 메시지보다 더 유용할 수 있습니다.

이 예시에서는 404410 상태 코드인 '찾을 수 없음' 'Gone'이 포함됩니다 이 중 하나가 수신되면 구독이 만료된 것입니다. 더 이상 유효하지 않습니다. 이 시나리오에서는 데이터베이스에서 구독을 삭제해야 합니다.

다른 오류가 발생한 경우에는 throw err만 사용하여 프라미스에서 반환하는 프로미스를 만듭니다. triggerPushMsg()이(가) 거부되었습니다.

다음 섹션에서 웹 푸시를 살펴볼 때 다른 상태 코드에 대해 다룰 것입니다. 자세히 살펴보겠습니다

구독을 순환한 후에는 JSON 응답을 반환해야 합니다.

.then(() => {
res.setHeader('Content-Type', 'application/json');
    res.send(JSON.stringify({ data: { success: true } }));
})
.catch(function(err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({
    error: {
    id: 'unable-to-send-messages',
    message: `We were unable to send messages to all subscriptions : ` +
        `'${err.message}'`
    }
}));
});

주요 구현 단계를 살펴보았습니다.

  1. API를 만들어 웹페이지에서 백엔드로 구독을 전송합니다. 데이터베이스에 저장할 수 있습니다
  2. 푸시 메시지 전송을 트리거하는 API를 만듭니다 (이 경우 API로 가장한 관리자 패널에서 호출됨).
  3. 백엔드에서 모든 구독 가져오기 web-push 구현 중 하나를 사용하여 각 구독에 메시지를 라이브러리를 참조하세요.

백엔드 (Node, PHP, Python 등)에 상관없이 푸시를 구현하는 단계는 변경할 수 있습니다.

다음으로, 이러한 웹 푸시 라이브러리는 정확히 어떤 역할을 할까요?

다음에 수행할 작업

Codelab