Salah satu titik masalah saat bekerja dengan web push adalah bahwa memicu pesan push dengan sangat "tidak jelas". Untuk memicu pesan push, aplikasi perlu membuat permintaan POST ke layanan push dengan mengikuti protokol push web. Untuk menggunakan push di semua browser, Anda harus menggunakan VAPID (alias kunci server aplikasi) yang pada dasarnya memerlukan penetapan header dengan nilai yang membuktikan bahwa aplikasi Anda dapat mengirim pesan kepada pengguna. Untuk mengirim data dengan pesan push, data harus dienkripsi dan header tertentu harus ditambahkan agar browser dapat mendekripsi pesan dengan benar.
Masalah utama saat memicu push adalah jika Anda mencapai masalah, akan sulit untuk mendiagnosis masalah tersebut. Hal ini meningkat seiring waktu dan dukungan browser yang lebih luas, tetapi hal ini jauh dari mudah. Karena alasan ini, sebaiknya gunakan library untuk menangani enkripsi, pemformatan, dan pemicu pesan push Anda.
Jika Anda benar-benar ingin mempelajari apa yang dilakukan library, kita akan membahasnya di bagian berikutnya. Untuk saat ini, kita akan melihat cara mengelola langganan dan menggunakan library push web yang ada untuk membuat permintaan push.
Di bagian ini, kita akan menggunakan library Node web-push. Bahasa lain mungkin memiliki perbedaan, tapi tidak akan terlalu berbeda. Kita mempelajari Node karena itu adalah JavaScript dan seharusnya menjadi yang paling mudah diakses oleh pembaca.
Kita akan melakukan langkah-langkah berikut:
- Kirim langganan ke backend kami dan simpan.
- Mengambil langganan tersimpan dan memicu pesan push.
Menyimpan langganan
Menyimpan dan membuat kueri PushSubscription
dari database akan bervariasi bergantung pada bahasa sisi server dan pilihan database Anda, tetapi mungkin ada baiknya untuk melihat contoh cara melakukannya.
Di halaman web demo, PushSubscription
dikirim ke backend dengan membuat permintaan POST sederhana:
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.');
}
});
}
Server Express dalam demo kami memiliki pemroses permintaan yang cocok untuk endpoint /api/save-subscription/
:
app.post('/api/save-subscription/', function (req, res) {
Dalam rute ini, kami memvalidasi langganan hanya untuk memastikan permintaan tersebut baik-baik saja dan tidak penuh sampah memori:
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;
};
Jika langganan valid, kita perlu menyimpannya dan menampilkan respons JSON yang sesuai:
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.',
},
}),
);
});
Demo ini menggunakan nedb untuk menyimpan langganan. Ini adalah database berbasis file yang sederhana, tetapi Anda dapat menggunakan database apa pun pilihan Anda. Kita hanya menggunakan ini karena tidak perlu pengaturan sama sekali. Untuk produksi, sebaiknya gunakan sesuatu yang lebih dapat diandalkan. (Saya cenderung menggunakan My MySQL lama yang bagus.)
function saveSubscriptionToDatabase(subscription) {
return new Promise(function (resolve, reject) {
db.insert(subscription, function (err, newDoc) {
if (err) {
reject(err);
return;
}
resolve(newDoc._id);
});
});
}
Mengirim pesan push
Dalam hal pengiriman pesan push, kita pada akhirnya memerlukan beberapa peristiwa untuk memicu proses pengiriman pesan kepada pengguna. Pendekatan umumnya adalah membuat halaman admin yang memungkinkan Anda
mengonfigurasi dan memicu pesan push. Namun, Anda dapat membuat program untuk dijalankan secara lokal atau
pendekatan lain yang memungkinkan akses ke daftar PushSubscription
dan menjalankan kode untuk
memicu pesan push.
Demo kami memiliki halaman "suka admin" yang memungkinkan Anda memicu push. Karena ini hanyalah demo, maka ini adalah halaman publik.
Saya akan menjelaskan setiap langkah yang diperlukan agar demo ini berfungsi. Ini akan menjadi langkah awal sehingga semua orang dapat mengikutinya, termasuk siapa saja yang baru menggunakan Node.
Saat membahas berlangganan pengguna, kita telah membahas penambahan applicationServerKey
ke opsi subscribe()
. Di bagian belakang kita akan
membutuhkan kunci pribadi ini.
Dalam demo, nilai-nilai ini ditambahkan ke aplikasi Node kami seperti itu (kode membosankan yang saya tahu, tetapi hanya ingin Anda tahu bahwa tidak ada keajaiban):
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
Selanjutnya, kita perlu menginstal modul web-push
untuk server Node:
npm install web-push --save
Kemudian, dalam skrip Node, kami memerlukan modul web-push
seperti berikut:
const webpush = require('web-push');
Sekarang kita dapat mulai menggunakan modul web-push
. Pertama, kita perlu memberi tahu modul web-push
tentang
kunci server aplikasi. (Ingat, kunci ini juga dikenal sebagai kunci VAPID karena merupakan nama spesifikasi.)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
Perhatikan bahwa kami juga menyertakan string "mailto:". String ini harus berupa URL atau alamat email mailto. Informasi ini sebenarnya akan dikirim ke layanan web push sebagai bagian dari permintaan untuk memicu push. Alasan hal ini dilakukan adalah agar jika layanan web push perlu menghubungi pengirim, layanan tersebut memiliki beberapa informasi yang memungkinkan mereka melakukannya.
Setelah proses ini, modul web-push
siap digunakan, langkah berikutnya adalah memicu pesan push.
Demo menggunakan panel admin palsu untuk memicu pesan push.
Mengklik tombol "Trigger Push Message" akan membuat permintaan POST ke /api/trigger-push-msg/
,
yang merupakan sinyal bagi backend kita untuk mengirim pesan push. Jadi, kita membuat rute
secara ekspres untuk endpoint ini:
app.post('/api/trigger-push-msg/', function (req, res) {
Saat permintaan ini diterima, kita mengambil langganan dari database dan untuk setiap langganan, kita memicu pesan push.
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;
});
Fungsi triggerPushMsg()
kemudian dapat menggunakan library web-push untuk mengirim pesan ke
langganan yang disediakan.
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;
}
});
};
Panggilan ke webpush.sendNotification()
akan menampilkan promise. Jika pesan berhasil dikirim, promise akan diselesaikan dan tidak ada yang perlu kami lakukan. Jika promise ditolak, Anda perlu memeriksa error tersebut karena akan memberi tahu Anda apakah PushSubscription
masih valid atau tidak.
Untuk menentukan jenis kesalahan dari layanan push, sebaiknya lihat kode status. Pesan error bervariasi antara layanan push dan beberapa lebih membantu daripada yang lain.
Dalam contoh ini, pemeriksaan kode status 404
dan 410
, yang merupakan kode status HTTP untuk 'Not Found' dan 'Gone'. Jika kami menerima salah satunya, berarti langganan telah habis masa berlakunya
atau tidak lagi valid. Dalam skenario ini, kita perlu menghapus langganan dari database.
Jika terjadi error lainnya, kita hanya perlu throw err
, yang akan membuat promise yang ditampilkan oleh triggerPushMsg()
ditolak.
Kami akan membahas beberapa kode status lain di bagian berikutnya saat membahas protokol web push secara lebih mendetail.
Setelah melakukan loop langganan, kita perlu menampilkan respons 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}'`
}
}));
});
Kita telah membahas langkah-langkah penerapan utama:
- Buat API untuk mengirim langganan dari halaman web ke back-end sehingga dapat menyimpannya ke database.
- Buat API untuk memicu pengiriman pesan push (dalam hal ini, API yang dipanggil dari panel admin palsu).
- Ambil semua langganan dari backend kami dan kirim pesan ke setiap langganan dengan salah satu library web-push.
Terlepas dari backend Anda (Node, PHP, Python, ...), langkah-langkah untuk menerapkan push akan sama.
Selanjutnya, apa sebenarnya yang dilakukan library web-push ini bagi kita?
Langkah berikutnya
- Ringkasan Notifikasi Push Web
- Cara Kerja Push
- Membuat Langganan Pengguna
- UX Izin
- Mengirim Pesan dengan Web Push Library
- Protokol Push Web
- Menangani Peristiwa Push
- Menampilkan Notifikasi
- Perilaku Notifikasi
- Pola Notifikasi Umum
- FAQ Notifikasi Push
- Masalah Umum dan Melaporkan Bug