वेब पुश लाइब्रेरी से मैसेज भेजना

वेब पुश के साथ काम करते समय सबसे बड़ी दिक्कत यह है कि पुश मैसेज ट्रिगर करना "बेफ़िक्र होकर" होता है. किसी पुश मैसेज को ट्रिगर करने के लिए, किसी ऐप्लिकेशन को वेब पुश प्रोटोकॉल का पालन करके, पुश सेवा के लिए POST अनुरोध करना होगा. सभी ब्राउज़र में पुश का इस्तेमाल करने के लिए, आपको VAPID (यानी ऐप्लिकेशन सर्वर कुंजियां) का इस्तेमाल करना होगा. इसमें हेडर सेट करना ज़रूरी होता है. साथ ही, इसमें ऐसी वैल्यू सेट करनी होगी जिससे यह साबित हो सके कि आपका ऐप्लिकेशन उपयोगकर्ता को मैसेज भेज सकता है. पुश मैसेज के साथ डेटा भेजने के लिए, डेटा को एन्क्रिप्ट (सुरक्षित) किया जाना चाहिए. साथ ही, खास हेडर जोड़ने होंगे, ताकि ब्राउज़र मैसेज को सही तरीके से डिक्रिप्ट कर सके.

पुश ट्रिगर करने की मुख्य समस्या यह है कि अगर आपको कोई समस्या आती है, तो उस समस्या का पता लगाना मुश्किल होता है. यह समय और ज़्यादा ब्राउज़र सहायता की वजह से बेहतर हो रहा है, लेकिन यह काफ़ी आसान है. इस वजह से, हमारा सुझाव है कि पुश मैसेज के एन्क्रिप्शन, फ़ॉर्मैटिंग, और ट्रिगर को मैनेज करने के लिए, लाइब्रेरी का इस्तेमाल करें.

अगर आपको यह जानना है कि लाइब्रेरी क्या कर रही हैं, तो हम इसके बारे में अगले सेक्शन में बताएंगे. फ़िलहाल, हम सदस्यताओं को मैनेज करने और पुश अनुरोधों को पूरा करने के लिए, मौजूदा वेब पुश लाइब्रेरी का इस्तेमाल करने वाले हैं.

इस सेक्शन में हम वेब-पुश नोड लाइब्रेरी का इस्तेमाल करेंगे. अन्य भाषाओं में अंतर होगा, लेकिन वे बहुत ज़्यादा अलग नहीं होंगे. हम Node को बनाने की कोशिश कर रहे हैं, क्योंकि यह JavaScript है और यह पाठकों के लिए सबसे ज़्यादा ऐक्सेस करने लायक होना चाहिए.

हम नीचे दिए गए चरणों को पूरा करेंगे:

  1. हमारे बैकएंड पर सदस्यता भेजें और उसे सेव करें.
  2. सेव की गई सदस्यताएं वापस पाएं और पुश मैसेज ट्रिगर करें.

सदस्यताएं सेव की जा रही हैं

PushSubscription को डेटाबेस से सेव और क्वेरी करना, आपके सर्वर साइड की भाषा और डेटाबेस की पसंद के हिसाब से अलग-अलग होगा. हालांकि, इसे कैसे किया जा सकता है, इसका उदाहरण देखना मददगार हो सकता है.

डेमो वेब पेज में, एक आसान पोस्ट अनुरोध करके 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.');
      }
    });
}

हमारे डेमो में एक्सप्रेशन सर्वर में, /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.',
        },
      }),
    );
  });

इस डेमो में सदस्यताओं की जानकारी को सेव करने के लिए, newb का इस्तेमाल किया गया है. यह फ़ाइल पर आधारित एक आसान डेटाबेस है, लेकिन आपके पास अपनी पसंद के किसी भी डेटाबेस का इस्तेमाल करने का विकल्प है. हम इसका इस्तेमाल सिर्फ़ इसलिए कर रहे हैं, क्योंकि इसे सेट अप करने की ज़रूरत नहीं है. प्रोडक्शन के लिए, हो सकता है कि आप किसी ज़्यादा भरोसेमंद चीज़ का इस्तेमाल करना चाहें. (मैं पुराने अच्छे 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 की सूची को ऐक्सेस किया जा सके और पुश मैसेज ट्रिगर करने के लिए, कोड को चलाया जा सके.

हमारे डेमो में "एडमिन जैसा" पेज मौजूद है, जिसकी मदद से पुश नोटिफ़िकेशन ट्रिगर किया जा सकता है. यह सिर्फ़ एक डेमो है. इसलिए, यह एक सार्वजनिक पेज है.

मैं डेमो को चालू करने के हर चरण पर बात करूंगा. ये छोटे-छोटे चरणों वाले होंगे, ताकि सभी लोग इनका पालन कर सकें. इनमें वे लोग भी शामिल हैं जो Node के लिए नए हैं.

जब हमने किसी उपयोगकर्ता की सदस्यता लेने के बारे में बात की थी, तब हमने subscribe() विकल्पों में applicationServerKey जोड़ने के बारे में बात की थी. बैक एंड पर हमें इस निजी कुंजी की ज़रूरत होगी.

डेमो में, ये वैल्यू हमारे Node ऐप्लिकेशन में इस तरह जोड़ी गई हैं (यह बोरिंग कोड है, लेकिन आपको बस यह बताना है कि यहां कोई जादू नहीं किया गया):

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

इसके बाद, हमें अपने नोड सर्वर के लिए web-push मॉड्यूल इंस्टॉल करना होगा:

npm install web-push --save

इसके बाद, हमें अपनी नोड स्क्रिप्ट में 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:" स्ट्रिंग भी शामिल की है. यह स्ट्रिंग या तो यूआरएल या 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() फ़ंक्शन, वेब-पुश लाइब्रेरी का इस्तेमाल करके, दी गई सदस्यता को मैसेज भेज सकता है.

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 अब भी मान्य है या नहीं.

यह पता लगाने के लिए कि पुश सेवा से जुड़ी गड़बड़ी किस तरह की है, स्टेटस कोड देखना बेहतर होगा. अलग-अलग पुश सेवाओं के लिए गड़बड़ी के मैसेज अलग-अलग होते हैं और कुछ मैसेज दूसरों के मुकाबले ज़्यादा काम के होते हैं.

इस उदाहरण में, यह स्टेटस कोड 404 और 410 की जांच करता है. ये 'नहीं मिला' और ' चला गया' के लिए, एचटीटीपी स्टेटस कोड हैं. अगर हमें इनमें से कोई भी मैसेज मिलता है, तो इसका मतलब है कि सदस्यता खत्म हो गई है या अब मान्य नहीं है. ऐसे में, हमें अपने डेटाबेस से सदस्यताएं हटानी होंगी.

किसी दूसरी गड़बड़ी के मामले में, हम सिर्फ़ 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. हमारे वेब पेज से सदस्यताओं को हमारे बैक-एंड पर भेजने के लिए, एक एपीआई बनाएं. इससे उन सदस्यताओं को डेटाबेस में सेव किया जा सकेगा.
  2. पुश मैसेज भेजने के लिए एपीआई बनाएं (इस मामले में, एडमिन पैनल से कॉल किया गया एपीआई).
  3. हमारे बैकएंड से सभी सदस्यताएं वापस पाएं और वेब-पुश लाइब्रेरी में से किसी एक की मदद से हर सदस्यता को मैसेज भेजें.

आपका बैकएंड (नोड, PHP, Python, ...) कुछ भी हो, पुश लागू करने के चरण एक जैसे ही रहेंगे.

आगे, जानते हैं कि ये वेब-पुश लाइब्रेरी असल में हमारे लिए क्या कर रही हैं?

आगे कहां जाना है

कोड लैब