Salah satu titik masalah saat menggunakan push web adalah memicu pesan push sangat "rumit". Untuk memicu pesan push, aplikasi harus membuat permintaan POST ke layanan push 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 perlu ditambahkan agar browser dapat mendekripsi pesan dengan benar.
Masalah utama dengan memicu push adalah jika Anda mengalami masalah, akan sulit untuk mendiagnosis masalah tersebut. Hal ini akan semakin baik seiring waktu dan dukungan browser yang lebih luas, tetapi prosesnya tidak mudah. Oleh karena itu, sebaiknya gunakan library untuk menangani enkripsi, pemformatan, dan pemicuan 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 push web. Bahasa lain akan memiliki perbedaan, tetapi tidak akan terlalu berbeda. Kita melihat Node karena merupakan JavaScript dan seharusnya paling mudah diakses oleh pembaca.
Kita akan membahas langkah-langkah berikut:
- Kirim langganan ke backend dan simpan langganan tersebut.
- Mengambil langganan yang 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 sebaiknya lihat
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) {
Di rute ini, kita memvalidasi langganan hanya untuk memastikan permintaannya baik dan tidak penuh dengan sampah:
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 sederhana, tetapi Anda dapat menggunakan database apa pun pilihan Anda. Kita hanya menggunakannya karena tidak memerlukan penyiapan apa pun. Untuk produksi, Anda ingin menggunakan sesuatu yang lebih dapat diandalkan. (Saya cenderung tetap menggunakan 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 mengirim pesan push, pada akhirnya kita memerlukan beberapa peristiwa untuk memicu proses
pengiriman pesan kepada pengguna. Pendekatan yang umum 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, halaman ini adalah halaman publik.
Saya akan membahas setiap langkah yang terlibat dalam menjalankan demo. Ini akan menjadi langkah kecil sehingga semua orang dapat mengikutinya, termasuk siapa saja yang baru menggunakan Node.
Saat membahas cara membuat pengguna berlangganan, kita telah membahas cara menambahkan applicationServerKey
ke opsi subscribe()
. Di backend, kita akan memerlukan kunci pribadi ini.
Dalam demo, nilai ini ditambahkan ke aplikasi Node kita seperti ini (kode yang membosankan, saya tahu, tetapi hanya ingin memberi tahu Anda 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, kita memerlukan modul web-push
seperti ini:
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 kita. (Ingat, kunci ini juga dikenal sebagai kunci VAPID karena itulah nama spesifikasinya.)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
Perhatikan bahwa kita juga menyertakan string "mailto:". String ini harus berupa URL atau alamat email mailto. Bagian informasi ini sebenarnya akan dikirim ke layanan push web sebagai bagian dari permintaan untuk memicu push. Alasan hal ini dilakukan adalah agar jika layanan push web perlu menghubungi pengirim, layanan tersebut memiliki beberapa informasi yang akan memungkinkannya melakukannya.
Dengan ini, modul web-push
siap digunakan, langkah berikutnya adalah memicu pesan push.
Demo ini 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 untuk mengirim pesan push, sehingga kita membuat rute di express 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 kita lakukan. Jika promise ditolak, Anda perlu memeriksa
error karena akan memberi tahu Anda apakah PushSubscription
masih
valid atau tidak.
Untuk menentukan jenis error dari layanan push, sebaiknya lihat kode status. Pesan error bervariasi di antara layanan push dan beberapa pesan lebih membantu daripada yang lain.
Dalam contoh ini, kode status 404
dan 410
diperiksa, yang merupakan kode status HTTP untuk
'Not Found' dan 'Gone'. Jika kami menerima salah satu pesan ini, artinya langganan sudah habis masa berlakunya
atau tidak lagi valid. Dalam skenario ini, kita perlu menghapus langganan dari database.
Jika terjadi beberapa error lain, kita hanya throw err
, yang akan membuat promise yang ditampilkan oleh triggerPushMsg()
ditolak.
Kita akan membahas beberapa kode status lainnya di bagian berikutnya saat kita melihat protokol push web secara lebih mendetail.
Setelah melakukan loop pada 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 backend agar dapat menyimpannya ke database.
- Buat API untuk memicu pengiriman pesan push (dalam hal ini, API yang dipanggil dari panel admin yang disimulasikan).
- Ambil semua langganan dari backend kami dan kirim pesan ke setiap langganan dengan salah satu library push web.
Apa pun backend Anda (Node, PHP, Python, …), langkah-langkah untuk menerapkan push akan sama.
Selanjutnya, apa sebenarnya yang dilakukan library push web ini untuk kita?
Langkah berikutnya
- Ringkasan Notifikasi Push Web
- Cara Kerja Push
- Berlangganan Pengguna
- UX Izin
- Mengirim Pesan dengan Library Push Web
- Protokol Web Push
- Menangani Peristiwa Push
- Menampilkan Notifikasi
- Perilaku Notifikasi
- Pola Notifikasi Umum
- FAQ Notifikasi Push
- Masalah Umum dan Bug Pelaporan