Web push'iyle çalışırken karşılaşılan sorunlardan biri, push mesajını tetiklemenin son derece "zor" olmasıdır. Bir uygulamanın push mesajı tetiklemesi için web push protokolüne uygun olarak bir push hizmetine POST isteği göndermesi gerekir. Tüm tarayıcılarda push özelliğini kullanmak için VAPID (uygulama sunucusu anahtarları olarak da bilinir) kullanmanız gerekir. Bu işlem temel olarak, uygulamanızın bir kullanıcıya mesaj gönderebileceğini kanıtlayan bir değere sahip bir başlık ayarlamanızı gerektirir. Verileri push mesajıyla göndermek için verilerin şifrelenmesi ve tarayıcının mesajın şifresini doğru şekilde çözebilmesi için belirli üstbilgilerin eklenmesi gerekir.
Push'i tetiklemenin en büyük sorunu, bir sorunla karşılaşırsanız sorunu teşhis etmenin zor olmasıdır. Bu durum, zaman içinde ve daha geniş kapsamlı tarayıcı desteğiyle iyileşiyor, ancak kolay bir işlem değil. Bu nedenle, push mesajınızın şifrelenmesi, biçimlendirilmesi ve tetiklenmesi için bir kitaplık kullanmanızı önemle tavsiye ederiz.
Kitaplıkların ne yaptığı hakkında daha fazla bilgi edinmek istiyorsanız bunu bir sonraki bölümde ele alacağız. Şimdilik aboneliklerin yönetilmesine ve push isteklerinde bulunmak için mevcut bir web push kitaplığının nasıl kullanılacağına bakacağız.
Bu bölümde web-push Node kitaplığını kullanacağız. Diğer diller arasında farklılıklar olsa da bu farklılıklar çok fazla olmaz. JavaScript olduğu ve okuyucular için en erişilebilir seçenek olması gerektiği için Node'u inceliyoruz.
Aşağıdaki adımları uygulayacağız:
- Arka uçımıza bir abonelik gönderip kaydedin.
- Kayıtlı abonelikleri alma ve push mesajı tetikleme.
Abonelikleri kaydetme
Bir veritabanından PushSubscription
öğelerini kaydetme ve sorgulama, sunucu tarafı dilinize ve veritabanı seçiminize bağlı olarak değişiklik gösterir. Ancak bunun nasıl yapılacağına dair bir örnek görmek yararlı olabilir.
Demo web sayfasında PushSubscription
, basit bir POST isteği yapılarak arka ucumuza gönderilir:
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.');
}
});
}
Demo'daki Express sunucusunda, /api/save-subscription/
uç noktası için eşleşen bir istek dinleyicisi vardır:
app.post('/api/save-subscription/', function (req, res) {
Bu yönde, isteğin iyi olduğundan ve gereksiz veri içermediğinden emin olmak için aboneliği doğrularız:
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;
};
Abonelik geçerliyse kaydedip uygun bir JSON yanıtı döndürmemiz gerekir:
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.',
},
}),
);
});
Bu demoda, abonelikleri depolamak için nedb kullanılır. Basit bir dosya tabanlı veritabanı olan nedb yerine dilediğiniz veritabanını kullanabilirsiniz. Bu yöntemi yalnızca sıfır kurulum gerektirdiği için kullanıyoruz. Üretim için daha güvenilir bir yöntem kullanmanız gerekir. (Ben eski MySQL'i kullanmaya devam ediyorum.)
function saveSubscriptionToDatabase(subscription) {
return new Promise(function (resolve, reject) {
db.insert(subscription, function (err, newDoc) {
if (err) {
reject(err);
return;
}
resolve(newDoc._id);
});
});
}
Push mesajları gönderme
Push mesajı gönderme söz konusu olduğunda, kullanıcılara mesaj gönderme sürecini tetikleyecek bir etkinliğe ihtiyacımız vardır. Yaygın bir yaklaşım, push mesajını yapılandırmanıza ve tetiklemenize olanak tanıyan bir yönetici sayfası oluşturmaktır. Ancak yerel olarak çalışacak bir program veya PushSubscription
listesine erişip itme mesajını tetiklemek için kodu çalıştırmaya olanak tanıyan başka bir yaklaşım oluşturabilirsiniz.
Demomuzda, push bildirimleri tetiklemenize olanak tanıyan "yönetici benzeri" bir sayfa bulunur. Bu yalnızca bir demo olduğu için herkese açık bir sayfadır.
Demonun çalışması için gereken her adımı anlatacağım. Bu adımlar, Node'a yeni başlayanlar da dahil olmak üzere herkesin takip edebilmesi için basit olacak.
Kullanıcı aboneliğinden bahsettiğimizde subscribe()
seçeneklerine applicationServerKey
eklemeyi ele almıştık. Bu özel anahtara arka uçta ihtiyacımız olacak.
Demoda bu değerler Node uygulamamıza aşağıdaki gibi eklenir (Biliyorum, sıkıcı bir kod ama sihirli bir şey olmadığını bilmenizi isterim):
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
Ardından, düğüm sunucumuz için web-push
modülünü yüklememiz gerekir:
npm install web-push --save
Ardından, Node komut dosyamızda web-push
modülünün şu şekilde olması gerekir:
const webpush = require('web-push');
Artık web-push
modülünü kullanmaya başlayabiliriz. Öncelikle web-push
modülüne uygulama sunucu anahtarlarımız hakkında bilgi vermemiz gerekir. (Bu anahtarlar, spesifikasyonun adı VAPID olduğu için VAPID anahtarları olarak da bilinir.)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
"mailto:" dizesi de eklediğimizi unutmayın. Bu dizenin bir URL veya mailto e-posta adresi olması gerekir. Bu bilgi, aslında bir push tetikleme isteği kapsamında web push hizmetine gönderilir. Bunun nedeni, bir web push hizmetinin gönderenle iletişime geçmesi gerektiğinde bunu yapabilmesi için bazı bilgilere sahip olmasıdır.
Bu işlemle web-push
modülü kullanıma hazır hale gelir. Sonraki adım, bir push mesajı tetiklemektir.
Demoda, push mesajlarını tetiklemek için sanal yönetici paneli kullanılmaktadır.
"Push Mesajını Tetikle" düğmesini tıkladığınızda /api/trigger-push-msg/
adresine bir POST isteği gönderilir. Bu istek, arka uç sistemimizin push mesajları göndermesi için bir sinyaldir. Bu nedenle, bu uç nokta için express'te rotayı oluştururuz:
app.post('/api/trigger-push-msg/', function (req, res) {
Bu istek alındığında, abonelikleri veritabanından alırız ve her biri için bir push mesajı tetikleriz.
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()
işlevi daha sonra sağlanan aboneliğe mesaj göndermek için web push kitaplığını kullanabilir.
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()
çağrısı bir promise döndürür. Mesaj başarıyla gönderildiyse söz çözülür ve herhangi bir işlem yapmamız gerekmez. Söz reddedilirse PushSubscription
'ün geçerli olup olmadığı konusunda sizi bilgilendireceğinden hatayı incelemeniz gerekir.
Push hizmetinden gelen hatanın türünü belirlemek için durum koduna bakmak en iyisidir. Hata mesajları, push hizmetleri arasında değişiklik gösterir ve bazı mesajlar diğerlerinden daha faydalıdır.
Bu örnekte, "Bulunamadı" ve "Yok" için HTTP durum kodları olan 404
ve 410
durum kodları kontrol edilir. Bu hatalardan birini alırsak aboneliğin süresi dolmuş veya artık geçerli değil demektir. Bu tür durumlarda, abonelikleri veritabanımızdan kaldırmamız gerekir.
Başka bir hata olması durumunda throw err
yaparız. Bu durumda, triggerPushMsg()
tarafından döndürülen söz reddedilir.
Web push protokolünü daha ayrıntılı bir şekilde incelediğimiz sonraki bölümde diğer durum kodlarından bazılarını ele alacağız.
Aboneliklerde döngü oluşturduktan sonra bir JSON yanıtı döndürmemiz gerekir.
.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}'`
}
}));
});
Temel uygulama adımlarını ele aldık:
- Web sayfamızdan abonelikleri arka uçımıza gönderecek bir API oluşturun. Böylece abonelikler bir veritabanına kaydedilebilir.
- Push mesajlarının gönderilmesini tetikleyecek bir API oluşturun (bu durumda, sahte yönetici panelinden çağrılan bir API).
- Tüm abonelikleri arka uçtan alın ve web push kitaplıklarından biriyle her aboneliğe mesaj gönderin.
Arka uçunuzdan (Node, PHP, Python vb.) bağımsız olarak, push'i uygulama adımları aynı olacaktır.
Şimdi de bu web push kitaplıklarının bizim için tam olarak ne yaptığını öğrenelim.
Sonraki adımlar
- Web Push Bildirimlerine Genel Bakış
- Push bildirimleri nasıl çalışır?
- Kullanıcıları abone etme
- İzin kullanıcı deneyimi
- Web Push Kitaplıklarıyla Mesaj Gönderme
- Web Push Protokolü
- Push Etkinliklerini İşleme
- Bildirim görüntüleme
- Bildirim Davranışı
- Yaygın Bildirim Kalıpları
- Push bildirimleri ile ilgili SSS
- Sık Karşılaşılan Sorunlar ve Hata Bildirme