רישום משתמש

השלב הראשון הוא לקבל הרשאה מהמשתמש לשלוח לו הודעות בדחיפה, ואז נוכל להשיג PushSubscription.

כדי לעשות את זה, JavaScript API פועל לפי התהליך הלוגי, אז בואו נעבור על התהליך הלוגי.

זיהוי תכונות

תחילה עלינו לבדוק אם הדפדפן הנוכחי אכן תומך בהעברת הודעות בדחיפה. אפשר לבדוק אם ב-push יש תמיכה בשתי בדיקות פשוטות.

  1. מחפשים את serviceWorker ב-navigator.
  2. מחפשים את PushManager ב-window.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

התמיכה בדפדפנים הולכת וגדלה במהירות גם ב-Service Worker וגם בהודעות Push, אבל תמיד כדאי לזהות את שני הרכיבים האלה ולשפר בהדרגה את התמיכה.

רישום קובץ שירות (service worker)

באמצעות זיהוי התכונה, אנחנו יודעים שגם Service Workers וגם Push נתמכים. השלב הבא הוא "רישום" של קובץ השירות (service worker).

כשאנחנו רושמים Service Worker, אנחנו אומרים לדפדפן איפה נמצא קובץ ה-Service Worker. הקובץ הוא עדיין רק JavaScript, אבל הדפדפן "יעניק לו גישה" לממשקי ה-API של ה-Service Worker, כולל Push. ליתר דיוק, הדפדפן מריץ את הקובץ בסביבה של Service Worker.

כדי לרשום קובץ שירות (service worker), צריך לקרוא ל-navigator.serviceWorker.register() ולהעביר את הנתיב לקובץ שלנו. למשל:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

הפונקציה הזו אומרת לדפדפן שיש לנו קובץ שירות (service worker) ומה המיקום שלו. במקרה הזה, קובץ ה-Service Worker נמצא ב-/service-worker.js. מאחורי הקלעים, הדפדפן יבצע את השלבים הבאים לאחר הקריאה ל-register():

  1. מורידים את קובץ ה-Service Worker.

  2. מריצים את ה-JavaScript.

  3. אם הכול פועל כמו שצריך ואין שגיאות, ההבטחה שהוחזרה על ידי register() תיפתר. אם יש שגיאות מכל סוג שהוא, ההבטחה תידחה.

אם המערכת דוחה את register(), יש לבדוק שוב את ה-JavaScript כדי לאתר שגיאות הקלדה או שגיאות בכלי הפיתוח ל-Chrome.

כאשר הערך register() אכן מזוהה, הוא מחזיר ServiceWorkerRegistration. נשתמש ברישום הזה כדי לגשת ל-PushManager API.

תאימות דפדפן PushManager API

תמיכה בדפדפן

  • 42
  • 17
  • 44
  • 16

מקור

נשלחה בקשת הרשאה

רשמנו את קובץ השירות (service worker) שלנו ואנחנו מוכנים לרשום את המשתמש. השלב הבא הוא לקבל הרשאה מהמשתמש לשלוח לו הודעות בדחיפה.

ה-API לקבלת הרשאה הוא פשוט יחסית, החיסרון הוא שה-API שונה לאחרונה מביצוע קריאה חוזרת להחזרת הבטחה. הבעיה היא שאנחנו לא יכולים לדעת איזו גרסה של ה-API מיושמת בדפדפן הנוכחי, ולכן צריך להטמיע את שניהם ולטפל בשניהם.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

בקוד שלמעלה, קטע הקוד החשוב הוא הקריאה ל-Notification.requestPermission(). השיטה הזו תציג למשתמש:

בקשת הרשאה ב-Chrome במחשב ובנייד.

ברגע שהמשתמש יצר אינטראקציה עם בקשת ההרשאה על ידי לחיצה על 'אישור', 'חסימה' או פשוט סגירה שלה, תתקבל התוצאה כמחרוזת: 'granted', 'default' או 'denied'.

בקוד לדוגמה שלמעלה, ההבטחה שמוחזרת על ידי askPermission() פותרת את הבעיה אם ההרשאה ניתנה, אחרת אנחנו מחזירים הודעת שגיאה שגורמת לדחיית ההבטחה.

מקרה קצה אחד שבו עליך לטפל הוא מצב שבו המשתמש לוחץ על הלחצן 'חסימה'. במקרה כזה, אפליקציית האינטרנט לא תוכל לבקש שוב הרשאה מהמשתמש. הם יצטרכו 'לבטל את החסימה' ידנית של האפליקציה על ידי שינוי מצב ההרשאה שלה, הקבור בחלונית ההגדרות. חשבו היטב איך ומתי מבקשים הרשאה מהמשתמש, כי אם הוא ילחץ על חסימה, זו לא דרך קלה לבטל את ההחלטה.

החדשות הטובות הן שרוב המשתמשים שמחים להעניק הרשאה, כל עוד הם יודעים למה הם מבקשים את ההרשאה.

בהמשך נבדוק איך אתרים פופולריים מסוימים מבקשים הרשאה.

רישום משתמש באמצעות PushManager

אחרי שנרשום את קובץ השירות (service worker) שלנו ונקבל הרשאה, נוכל לרשום משתמש באמצעות registration.pushManager.subscribe().

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

כשמפעילים את השיטה subscribe(), אנחנו מעבירים אובייקט options שכולל גם פרמטרים נדרשים וגם פרמטרים אופציונליים.

עכשיו נבחן את כל האפשרויות שאנחנו יכולים להעביר.

אפשרויות משתמשגלוי בלבד

כשנוספה Push בפעם הראשונה לדפדפנים, היה חוסר ודאות לגבי היכולת של מפתחים לשלוח הודעת Push ולא להציג התראה. זה נקרא בדרך כלל דחיפה שקטה כי המשתמש לא יודע שמשהו קרה ברקע.

החשש היה שמפתחים יכלו לעשות דברים זדוניים כמו לעקוב אחר מיקום המשתמש על בסיס מתמשך מבלי לדעת על כך.

כדי למנוע את התרחיש הזה ולתת לכותבי המפרט זמן להחליט מהי הדרך הטובה ביותר לתמוך בתכונה הזו, נוספה האפשרות userVisibleOnly והעברת הערך true היא הסכמה סימבולית עם הדפדפן לכך שאפליקציית האינטרנט תציג התראה בכל פעם שמתקבלת דחיפה (כלומר, בלי דחיפה שקטה).

בשלב זה חובה להעביר את הערך true. אם לא כוללים את המפתח או את הכרטיס userVisibleOnly ב-false, תתקבל הודעת השגיאה הבאה:

Chrome תומך כרגע ב-Push API רק עבור מינויים שיובילו להצגת הודעות למשתמשים. כדי לציין זאת, אפשר להתקשר ל-pushManager.subscribe({userVisibleOnly: true}) במקום זאת. מידע נוסף זמין בכתובת https://goo.gl/yqv4Q4.

כרגע נראה שדחיפה שקטה גורפת לעולם לא תיושם ב-Chrome. במקום זאת, מחברי מפרטים בוחנים את הרעיון של API לתקציב, שיאפשר לאפליקציות אינטרנט להשתמש במספר מסוים של הודעות דחיפת הודעות שקטות, על סמך השימוש באפליקציית אינטרנט.

אפשרות applicationServerKey

הזכרנו בקצרה את "מפתחות שרת האפליקציות" בקטע הקודם. 'מפתחות שרת אפליקציות' משמשים שירות Push כדי לזהות את האפליקציה שרושם משתמש, ולהבטיח שאותה אפליקציה מעבירה הודעות למשתמש.

מפתחות של שרת אפליקציות הם זוג מפתחות ציבורי ופרטי וייחודי לאפליקציה שלכם. המפתח הפרטי צריך להיות סודי לאפליקציה שלכם, וניתן לשתף את המפתח הציבורי באופן חופשי.

האפשרות applicationServerKey שמועברת בקריאה ל-subscribe() היא המפתח הציבורי של האפליקציה. הדפדפן מעביר אותו לשירות דחיפה כשרושמים את המשתמש. כלומר, שירות ה-Push יכול לקשור את המפתח הציבורי של האפליקציה ל-PushSubscription של המשתמש.

התרשים הבא ממחיש את השלבים האלה.

  1. אפליקציית האינטרנט נטענת בדפדפן, ואתם מפעילים את הפקודה subscribe() ומעבירים את המפתח של שרת האפליקציות הציבורי.
  2. לאחר מכן הדפדפן שולח בקשת רשת לשירות Push שייצור נקודת קצה (endpoint), משייך את נקודת הקצה הזו למפתח הציבורי של האפליקציה ומחזיר את נקודת הקצה לדפדפן.
  3. הדפדפן יוסיף את נקודת הקצה הזו ל-PushSubscription, שמוחזר דרך ההבטחה subscribe().

איור של המפתח הציבורי של שרת האפליקציות שבו משתמשים בשיטת ההרשמה.

כדי לשלוח הודעה בדחיפה, צריך ליצור כותרת Authorization שתכיל מידע שחתום באמצעות המפתח הפרטי של שרת האפליקציות שלכם. כששירות ה-push מקבל בקשה לשליחת הודעת Push, הוא יכול לאמת את כותרת ה-Authorization החתומה הזו על ידי חיפוש המפתח הציבורי שמקושר לנקודת הקצה שמקבלת את הבקשה. אם החתימה חוקית, שירות ה-Push יודע שהיא חייבת להגיע משרת האפליקציות עם המפתח הפרטי התואם. זהו אמצעי אבטחה שמונע מאנשים אחרים לשלוח הודעות למשתמשי אפליקציה.

איך משתמשים במפתח השרת הפרטי של האפליקציה כששולחים הודעה

מבחינה טכנית, applicationServerKey הוא אופציונלי. עם זאת, היישום הפשוט ביותר ב-Chrome מחייב זאת, ודפדפנים אחרים עשויים לדרוש זאת בעתיד. אם משתמשים ב-Firefox, זו אפשרות אופציונלית.

המפרט שמגדיר מה צריך להיות מפתח שרת האפליקציות הוא מפרט VAPID. בכל פעם שאתם קוראים משהו המתייחס ל"מפתחות שרת אפליקציות" או ל"מפתחות VAPID", חשוב לזכור שזה אותו דבר.

איך ליצור מפתחות לשרת אפליקציות

כדי ליצור קבוצה ציבורית ופרטית של מפתחות לשרת אפליקציות, נכנסים לכתובת web-push-codelab.glitch.me. אפשר גם להשתמש בשורת הפקודה web-push כדי ליצור מפתחות באמצעות הפעולות הבאות:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

אתם צריכים ליצור את המפתחות האלה רק פעם אחת באפליקציה, אבל רק ודאו שהמפתח הפרטי נשאר פרטי. (כן, בדיוק אמרתי את זה).

הרשאות ו-Subscribe()

יש תופעת לוואי אחת של התקשרות ל-subscribe(). אם לאפליקציית האינטרנט אין הרשאות להציג התראות בזמן הקריאה ל-subscribe(), הדפדפן יבקש את ההרשאות. האפשרות הזו שימושית אם ממשק המשתמש שלכם עובד עם התהליך הזה, אבל אם אתם רוצים יותר שליטה (ולדעתי רוב המפתחים עושים זאת), כדאי להישאר עם ה-API Notification.requestPermission() שבו השתמשנו קודם.

מהו מינוי Push?

אנחנו מפעילים את הפקודה subscribe(), מעבירים כמה אפשרויות ובתמורה מקבלים הבטחה שמובילה ל-PushSubscription וכתוצאה מכך מתקבל קוד כמו:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

האובייקט PushSubscription מכיל את כל המידע הנדרש כדי לשלוח הודעות Push למשתמש הזה. אם תדפיסו את התוכן באמצעות JSON.stringify(), תראו את הדברים הבאים:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint היא כתובת ה-URL של שירותי ה-Push. על מנת להפעיל הודעת Push, יש לשלוח בקשת POST לכתובת ה-URL הזו.

האובייקט keys מכיל את הערכים שמשמשים להצפנת נתוני הודעות שנשלחים באמצעות הודעת Push (בהמשך נדון בקטע הזה).

שליחת מינוי לשרת שלך

לאחר שיהיה לך מינוי Push, עליך לשלוח אותו לשרת שלך. זה תלוי בכם, אבל טיפ קטן הוא להשתמש ב-JSON.stringify() כדי להוציא את כל הנתונים הנחוצים מאובייקט המינוי. לחלופין, אפשר לחבר את אותה תוצאה באופן ידני כך:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(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.');
      }
    });
}

שרת הצמתים מקבל את הבקשה הזו ושומר את הנתונים במסד נתונים לשימוש במועד מאוחר יותר.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  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.',
          },
        }),
      );
    });
});

עם פרטי PushSubscription בשרת שלנו, אנחנו יכולים לשלוח הודעה למשתמשים בכל זמן.

שאלות נפוצות

כמה שאלות נפוצות שאנשים שאלו בשלב זה:

האם אפשר לשנות את שירות ה-Push בדפדפן?

לא. שירות ה-Push נבחר על ידי הדפדפן, וכפי שראינו עם הקריאה subscribe(), הדפדפן ישלח בקשות רשת לשירות ה-Push כדי לאחזר את הפרטים שמהם מורכב ה-PushSubscription.

כל דפדפן משתמש בשירות Push שונה, נכון שיש לו API שונה?

כל שירותי ה-Push יצפו לאותו API.

ה-API הנפוץ הזה נקרא Web Push Protocol, והוא מתאר את בקשת הרשת שהאפליקציה תצטרך לשלוח על מנת להפעיל הודעת Push.

אם נרשמתי למשתמש דרך המחשב, האם הוא נרשם גם בטלפון שלו?

לצערנו לא. משתמש צריך להירשם לדחיפה בכל דפדפן שבו הוא רוצה לקבל הודעות. חשוב גם לציין שנדרשת הרשאה מהמשתמש בכל מכשיר.

השלבים הבאים

שיעורי Lab