Push bildirimleri sunucusu oluşturma

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

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

Yerleşik Glitch uygulamasında bildirimler otomatik olarak engellenir. Bu nedenle, uygulamayı bu sayfada ö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, ardından Tam Ekran'a tam ekran basın.

Canlı uygulama yeni bir Chrome sekmesinde açılır. Kodu tekrar göstermek için yerleşik Glitch'te Kaynağı Görüntüle'yi tıklayın.

Bu kod laboratuvarını tamamlarken bu sayfadaki yerleşik Glitch'teki kodda değişiklikler 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 "Kontrol+Üst Karakter+J" (veya Mac'te "Komut+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ı kaydetme, 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. Buna bir push aboneliği eklenmişse push aboneliği de devre dışı bırakılır.

    • Push'a abone olun, bir push aboneliği oluşturur. Bu işlev yalnızca bir hizmet çalışanı kaydedildiğinde ve istemci kodunda bir VAPID_PUBLIC_KEY sabit değeri bulunduğunda kullanılabilir (bu konu hakkında daha sonra daha fazla bilgi verilecektir). Bu nedenle, henüz tıklayamazsınız.

    • Etkin bir push aboneliğiniz varsa Mevcut aboneliği bilgilendir, 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ı etkin olmayabilir. Sunucu, aboneliğe bildirim gönderene kadar aboneliğin kaldırılması her zaman mümkündür.

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'i tıklayın.

    Muhtemelen Listening on port 3000 gibi bir mesaj görürsünüz.

    Canlı uygulama kullanıcı arayüzünde Mevcut aboneliği bildir veya Tüm abonelikleri bildir'i tıkladıysanız aşağıdaki mesajı da görürsünüz:

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

Şimdi bazı kodlara göz atalım.

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

    Yalnızca sunucu işleviyle çalışacağınız için bu dosyayı düzenlemeyeceksiniz (VAPID_PUBLIC_KEY sabit değerini doldurmak dışında).

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

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

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

  • server.js, bu codelab'de çalışmalarınız büyük kısmını yapacağınız dosyadır.

    Başlangıç kodu, basit bir Express web sunucusu oluşturur. Kod yorumlarında TODO: ile işaretlenmiş dört TODO öğeniz var. Şunları yapmanız gerekiyor:

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

VAPID ayrıntılarını oluşturun ve yükleyin

İlk yapılacak iş, 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 olurken uygulamanın ve sunucusunun kimliğine güvenmelidir. Ayrıca, kullanıcıların aldıkları bildirimlerin aboneliği oluşturan uygulamadan geldiğinden emin olmaları gerekir. Ayrıca, bildirim içeriğini başka kimsenin okuyamayacağından emin olmalıdır.

Push bildirimlerini güvenli ve gizli hale getiren protokole Web Push için İsteğe Bağlı Uygulama Sunucusu Kimliği (VAPID) adı verilir. 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 şifrelemek ve 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 Glitch arayüzünde Araçlar -> Günlükler'i seçin.

    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ışla birlikte ekrandan kaybolabilir.

  3. .env dosyasına 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" değerini 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 dosyasında 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 dosyasında, VAPID ayrıntılarını ortam değişkenlerinden 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. Herkese açık anahtarı da istemci koduna kopyalayıp yapıştırın.

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

    public/index.js

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

Bildirim gönderme işlevini uygulama

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 şifreler. Bu nedenle 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çenek 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 artık alakalı olmayan bir bildirimi kullanıcıya göndermesini önlemek için kullanılan bir yöntemdir.

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'e abone ol'u tıklar.

  2. İstemci, sunucunun herkese açık VAPID anahtarı olan VAPID_PUBLIC_KEY sabit değerini kullanarak sunucuya özgü benzersiz 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, dize haline getirilmiş subscription öğesini POST isteğinin gövdesinden alır, JSON'a dönüştürür ve abonelikler veritabanına ekler.

    Veritabanı, abonelikleri anahtar olarak kendi uç noktalarını kullanarak 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 sunucu, bildirimleri göndermek için yeni aboneliği kullanabilir.

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);
});

Bu işleyici, uygulamanızda şunları yapmalıdır:

  • Yeni aboneliği, istek metninden alın.
  • Etkin aboneliklerin veritabanına erişme.
  • Yeni aboneliği etkin abonelikler listesine ekleyin.

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 işleme

Arka plan

Sunucu, bir aboneliğin ne zaman etkin olmadığını her zaman bilemez. Örneğin, tarayıcı servis çalışanını kapattığında 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. Bu, basit bir test uygulamasında pek önemli olmasa da daha büyük ölçekte önemli hale gelir.

Uygulama

Abonelik iptal istekleri /remove-subscription POST URL'sine gönderilir.

server.js dosyasında bulunan stub rota işleyici şu şekilde görünür:

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);
});

Bu işleyici, uygulamanızda şunları yapmalıdır:

  • İ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övdesinde, kaldırmanız gereken uç nokta bulunur:

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

Abonelik iptallerini işlemek için:

  • server.js dosyasında, /remove-subscription için rota işleyiciyi aşağıdaki gibi 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);
 
});