Push bildirimleri sunucusu oluşturma

Bu codelab'de bir push bildirimi sunucusu oluşturacaksınız. Sunucu, push abonelikleri listesini yönetir ve bu aboneliklere bildirim gönderir.

İstemci kodu zaten tamamlanmıştır. Bu codelab'de sunucu tarafı işlevi üzerinde çalışacaksınız.

Örnek uygulamayı remiksleyip yeni bir sekmede görüntüleyin

Bildirimler, yerleşik Glitch uygulamasından otomatik olarak engellendiği için bu sayfada uygulamayı önizleyemezsiniz. Bunun yerine aşağıdakileri yapmanız gerekir:

  1. Projeyi düzenlenebilir hale getirmek için Düzenlemek için Remiks'i tıklayın.
  2. Siteyi önizlemek için Uygulamayı Görüntüle'ye basın. Ardından, Tam ekran tam ekran.

Canlı uygulama yeni bir Chrome sekmesinde açılır. Yerleştirilmiş arızada, kodun tekrar gösterilmesi için Kaynağı Görüntüle'yi tıklayın.

Bu codelab'de çalışırken bu sayfadaki yerleştirilmiş Glitch'te yer alan kodda değişiklik yapın. Değişiklikleri görmek için yeni sekmeyi yayındaki uygulamanızla yenileyin.

Başlangıç uygulaması ve kodu hakkında bilgi edinin

Öncelikle uygulamanın istemci kullanıcı arayüzüne göz atın.

Yeni Chrome sekmesinde:

  1. Geliştirici Araçları'nı açmak için "Control+Üst Karakter+J" (veya Mac'te "Command+Option+J") tuşlarına basın. Konsol sekmesini tıklayın.

  2. Kullanıcı arayüzündeki düğmeleri tıklamayı deneyin (çıktı için Chrome geliştirici konsolunu kontrol edin).

    • Hizmet çalışanını kaydet, Glitch proje URL'nizin kapsamı için bir hizmet çalışanı kaydeder. Hizmet çalışanının kaydını iptal et, hizmet çalışanını kaldırır. Bir push aboneliği eklenmişse push aboneliği de devre dışı bırakılır.

    • Push için abone ol seçeneği, bir push aboneliği oluşturur. Bu özellik, yalnızca bir hizmet çalışanı kaydedildiğinde ve istemci kodunda VAPID_PUBLIC_KEY sabiti varsa kullanılabilir (bununla ilgili daha fazla bilgi edinmek için daha sonra). Bu nedenle henüz tıklayamazsınız.

    • Etkin bir push aboneliğiniz olduğunda Mevcut aboneliği bilgilendir seçeneği, sunucunun uç noktasına bildirim göndermesini ister.

    • Tüm abonelikleri bildir seçeneği, sunucuya, veritabanındaki tüm abonelik uç noktalarına bildirim göndermesini söyler.

      Bu uç noktaların bazılarının etkin olmayabileceğini unutmayın. Sunucu, aboneye bildirim gönderdiğinde abonelik kaybolabilir.

Sunucu tarafında neler olduğuna bakalım. Sunucu kodundan gelen mesajları görmek için Glitch arayüzündeki Node.js günlüğüne bakın.

  • Glitch uygulamasında Araçlar -> Günlükler.

    Büyük olasılıkla Listening on port 3000 gibi bir mesaj görürsünüz.

    Canlı uygulamanın kullanıcı arayüzünde Mevcut aboneliği bildir veya Tüm abonelikleri bildir'i tıklamayı denerseniz de şu mesajı görürsünüz:

    TODO: Implement sendNotifications()
    Endpoints to send to:  []
    

Şimdi bir koda bakalım.

  • public/index.js, tamamlanmış istemci kodunu içeriyor. Özellik algılaması gerçekleştirir, hizmet çalışanının kaydını ve kaydını iptal eder ve kullanıcının push bildirimleri aboneliğini kontrol eder. Ayrıca, yeni ve silinen aboneliklerle ilgili bilgileri de sunucuya gönderir.

    Yalnızca sunucu işlevselliği üzerinde çalışacağınız için bu dosyayı düzenleyeceksiniz (VAPID_PUBLIC_KEY sabitini doldurma dışında).

  • public/service-worker.js, push etkinliklerini yakalayan ve bildirimleri görüntüleyen basit bir hizmet çalışanıdır.

  • /views/index.html, uygulamanın kullanıcı arayüzünü içerir.

  • .env, Glitch'in uygulama sunucunuza başlatıldığında sunucuya yüklediği ortam değişkenlerini içerir. Bildirim göndermek için .env alanını kimlik doğrulama ayrıntılarıyla doldurursunuz.

  • server.js, bu codelab'de ağırlıklı olarak iş yapacağınız dosyadır.

    Başlangıç kodu ile basit bir Ekspres web sunucusu oluşturulur. Kod yorumlarında TODO: ile işaretlenmiş dört Yapılacaklar öğesi var. Şunları yapmanız gerekiyor:

    Bu codelab'de, bu TODO öğeleri üzerinden birer birer çalışacaksınız.

VAPID ayrıntılarını oluşturma ve yükleme

YAPILACAK ilk öğe, VAPID ayrıntılarını oluşturmak, bunları Node.js ortam değişkenlerine eklemek ve istemci ile sunucu kodunu yeni değerlerle güncellemektir.

Arka plan

Kullanıcılar bildirimlere abone olduğunda uygulamanın kimliğine ve sunucusuna güvenmeleri gerekir. Ayrıca, kullanıcıların bir bildirim aldıklarında, bu bildirimin aboneliğin kurulumunu yapan uygulamadan geldiğinden emin olmaları gerekir. Ayrıca, bildirim içeriğini başka kimsenin okuyamayacağına da güvenmeleri gerekir.

Push bildirimlerini güvenli ve gizli hale getiren protokol Web Push için Gönüllü Uygulama Sunucusu Kimliği (VAPID) olarak adlandırılır. VAPID; uygulamaların, sunucuların ve abonelik uç noktalarının kimliğini doğrulamak ve bildirim içeriğini şifrelemek için ortak anahtar kriptografisini kullanır.

Bu uygulamada, VAPID anahtarları oluşturmak ve bildirimleri şifreleyip göndermek için web-push npm paketini kullanacaksınız.

Uygulama

Bu adımda, uygulamanız için bir VAPID anahtarı oluşturun ve bunları ortam değişkenlerine ekleyin. Ortam değişkenlerini sunucuya yükleyin ve ortak anahtarı, istemci koduna sabit değer olarak ekleyin.

  1. Bir VAPID anahtarı çifti oluşturmak için web-push kitaplığının generateVAPIDKeys işlevini kullanın.

    server.js'de, aşağıdaki kod satırlarında bulunan yorumları kaldırın:

    server.js

    // Generate VAPID keys (only do this once).
    /*
     * const vapidKeys = webpush.generateVAPIDKeys();
     * console.log(vapidKeys);
     */
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    
  2. Glitch, uygulamanızı yeniden başlattıktan sonra oluşturulan anahtarları Glitch arayüzündeki Node.js günlüğüne gönderir (Chrome konsoluna değil). VAPID anahtarlarını görmek için Araçlar -> Günlükler'i tıklayın.

    Genel ve özel anahtarlarınızı aynı anahtar çiftinden kopyaladığınızdan emin olun.

    Glitch, kodunuzu her düzenlediğinizde uygulamanızı yeniden başlatır. Bu nedenle, oluşturduğunuz ilk anahtar çifti, daha fazla çıkış arttıkça görünümden kayabilir.

  3. .env dosyasında, VAPID anahtarlarını kopyalayıp yapıştırın. Anahtarları çift tırnak ("...") içine alın.

    VAPID_SUBJECT için "mailto:test@test.test" girebilirsiniz.

    .env

    # process.env.SECRET
    VAPID_PUBLIC_KEY=
    VAPID_PRIVATE_KEY=
    VAPID_SUBJECT=
    VAPID_PUBLIC_KEY="BN3tWzHp3L3rBh03lGLlLlsq..."
    VAPID_PRIVATE_KEY="I_lM7JMIXRhOk6HN..."
    VAPID_SUBJECT="mailto:test@test.test"
    
  4. VAPID anahtarlarını yalnızca bir kez oluşturmanız gerektiğinden, server.js'de bu iki kod satırını tekrar yorumlayın.

    server.js

    // Generate VAPID keys (only do this once).
    /*
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    */
    const vapidKeys = webpush.generateVAPIDKeys();
    console.log(vapidKeys);
    
  5. server.js'de, ortam değişkenlerinden VAPID ayrıntılarını yükleyin.

    server.js

    const vapidDetails = {
      // TODO: Load VAPID details from environment variables.
      publicKey: process.env.VAPID_PUBLIC_KEY,
      privateKey: process.env.VAPID_PRIVATE_KEY,
      subject: process.env.VAPID_SUBJECT
    }
    
  6. Ortak anahtarı da kopyalayıp istemci koduna yapıştırın.

    public/index.js dosyasında, VAPID_PUBLIC_KEY için .env dosyasına kopyaladığınız aynı değeri girin:

    public/index.js

    // Copy from .env
    const VAPID_PUBLIC_KEY = '';
    const VAPID_PUBLIC_KEY = 'BN3tWzHp3L3rBh03lGLlLlsq...';
    ````
    
ziyaret edin.

Bildirim gönderme işlevini uygulayın

Arka plan

Bu uygulamada, bildirim göndermek için web-push npm paketini kullanacaksınız.

Bu paket, webpush.sendNotification() çağrıldığında bildirimleri otomatik olarak şifrelediği için bu konuda endişelenmenize gerek yoktur.

web-push, bildirimler için birden fazla seçeneği kabul eder. Örneğin, iletiye üstbilgi ekleyebilir ve içerik kodlaması belirtebilirsiniz.

Bu codelab'de yalnızca aşağıdaki kod satırlarıyla tanımlanan iki seçeneği kullanacaksınız:

let options = {
  TTL: 10000; // Time-to-live. Notifications expire after this.
  vapidDetails: vapidDetails; // VAPID keys from .env
};

TTL (geçerlilik süresi) seçeneği, bildirimde süre sonu zaman aşımını ayarlar. Bu, sunucunun ilgili kullanıcı artık alakalı olmadığında kullanıcıya bildirim göndermekten kaçınmasının bir yoludur.

vapidDetails seçeneği, ortam değişkenlerinden yüklediğiniz VAPID anahtarlarını içerir.

Uygulama

server.js'de sendNotifications işlevini aşağıdaki gibi değiştirin:

server.js

function sendNotifications(database, endpoints) {
  // TODO: Implement functionality to send notifications.
  console.log('TODO: Implement sendNotifications()');
  console.log('Endpoints to send to: ', endpoints);
  let notification = JSON.stringify(createNotification());
  let options = {
    TTL: 10000, // Time-to-live. Notifications expire after this.
    vapidDetails: vapidDetails // VAPID keys from .env
  };
  endpoints.map(endpoint => {
    let subscription = database[endpoint];
    webpush.sendNotification(subscription, notification, options);
  });
}

webpush.sendNotification() bir söz döndürdüğünden, hata işlemeyi kolayca ekleyebilirsiniz.

server.js'de sendNotifications işlevini tekrar değiştirin:

server.js

function sendNotifications(database, endpoints) {
  let notification = JSON.stringify(createNotification());
  let options = {
    TTL: 10000; // Time-to-live. Notifications expire after this.
    vapidDetails: vapidDetails; // VAPID keys from .env
  };
  endpoints.map(endpoint => {
    let subscription = database[endpoint];
    webpush.sendNotification(subscription, notification, options);
    let 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.body} `);
    });
  });
}

Yeni abonelikleri yönetme

Arka plan

Kullanıcı push bildirimlerine abone olduğunda şunlar gerçekleşir:

  1. Kullanıcı, Push için abone ol'u tıklar.

  2. İstemci, VAPID_PUBLIC_KEY sabitini (sunucunun genel VAPID anahtarı) kullanarak benzersiz, sunucuya özgü bir subscription nesnesi oluşturur. subscription nesnesi şöyle görünür:

       {
         "endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9...",
         "expirationTime": null,
         "keys":
         {
           "p256dh": "BNYDjQL9d5PSoeBurHy2e4d4GY0sGJXBN...",
           "auth": "0IyyvUGNJ9RxJc83poo3bA"
         }
       }
    
  3. İstemci, /add-subscription URL'sine, aboneliği gövdedeki dizeleştirilmiş JSON biçiminde de dahil olmak üzere bir POST isteği gönderir.

  4. Sunucu, dizeleştirilmiş subscription öğesini POST isteğinin gövdesinden alır, yeniden JSON olarak ayrıştırır ve abonelik veritabanına ekler.

    Veritabanı, kendi uç noktalarını anahtar olarak kullanarak abonelikleri depolar:

    {
      "https://fcm...1234": {
        endpoint: "https://fcm...1234",
        expirationTime: ...,
        keys: { ... }
      },
      "https://fcm...abcd": {
        endpoint: "https://fcm...abcd",
        expirationTime: ...,
        keys: { ... }
      },
      "https://fcm...zxcv": {
        endpoint: "https://fcm...zxcv",
        expirationTime: ...,
        keys: { ... }
      },
    }

Artık yeni abonelik bildirim göndermek için sunucu tarafından kullanılabilir.

Uygulama

Yeni abonelik istekleri, bir POST URL'si olan /add-subscription yoluna gelir. server.js'de bir saplama rota işleyicisi görürsünüz:

server.js

app.post('/add-subscription', (request, response) => {
  // TODO: implement handler for /add-subscription
  console.log('TODO: Implement handler for /add-subscription');
  console.log('Request body: ', request.body);
  response.sendStatus(200);
});

Uygulamanızda bu işleyici:

  • İsteğin gövdesinden yeni aboneliği alın.
  • Etkin aboneliklerin veritabanına erişme.
  • Yeni aboneliği etkin abonelikler listesine ekleyin.
ziyaret edin.

Yeni abonelikleri yönetmek için:

  • server.js'de, /add-subscription için rota işleyiciyi şu şekilde değiştirin:

    server.js

    app.post('/add-subscription', (request, response) => {
      // TODO: implement handler for /add-subscription
      console.log('TODO: Implement handler for /add-subscription');
      console.log('Request body: ', request.body);
      let subscriptions = Object.assign({}, request.session.subscriptions);
      subscriptions[request.body.endpoint] = request.body;
      request.session.subscriptions = subscriptions;
      response.sendStatus(200);
    });

Abonelik iptallerini yönetme

Arka plan

Sunucu, bir abonelik etkin olmayan abonelik durumuna geçtiğinde her zaman bunu bilmeyecektir. Örneğin, tarayıcı hizmet çalışanını kapattığında bir abonelik silinebilir.

Bununla birlikte sunucu, iptal edilen abonelikler hakkında uygulamanın kullanıcı arayüzü aracılığıyla bilgi edinebilir. Bu adımda, bir aboneliği veritabanından kaldırma işlevini uygulayacaksınız.

Bu şekilde sunucu, var olmayan uç noktalara bir dizi bildirim göndermekten kaçınır. Elbette bu, basit bir test uygulaması için çok önemli değildir, ancak daha geniş ölçekte önemli hale gelir.

Uygulama

Abonelik iptali istekleri /remove-subscription POST URL'sine gelir.

server.js'deki saplama rota işleyicisi şuna benzer:

server.js

app.post('/remove-subscription', (request, response) => {
  // TODO: implement handler for /remove-subscription
  console.log('TODO: Implement handler for /remove-subscription');
  console.log('Request body: ', request.body);
  response.sendStatus(200);
});

Uygulamanızda bu işleyici:

  • İptal edilen aboneliğin uç noktasını isteğin gövdesinden alın.
  • Etkin aboneliklerin veritabanına erişme.
  • İptal edilen aboneliği etkin abonelikler listesinden kaldırın.

İstemciden gelen POST isteğinin gövdesi, kaldırmanız gereken uç noktayı içerir:

{
  "endpoint": "https://fcm.googleapis.com/fcm/send/cpqAgzGzkzQ:APA9..."
}

Abonelik iptallerini işlemek için:

  • server.js'de, /remove-subscription için rota işleyiciyi şu şekilde değiştirin:

    server.js

  app.post('/remove-subscription', (request, response) => {
    // TODO: implement handler for /remove-subscription
    console.log('TODO: Implement handler for /remove-subscription');
    console.log('Request body: ', request.body);
    let subscriptions = Object.assign({}, request.session.subscriptions);
    delete subscriptions[request.body.endpoint];
    request.session.subscriptions = subscriptions;
    response.sendStatus(200);
  });