ปัญหาอย่างหนึ่งในการใช้งานพุชจากเว็บคือการทริกเกอร์ข้อความ Push นั้น "วุ่นวาย" เป็นอย่างมาก หากต้องการทริกเกอร์ข้อความพุช แอปพลิเคชันต้องส่งคำขอ POST ไปยังบริการพุชตามโปรโตคอลพุชจากเว็บ หากต้องการใช้พุชในเบราว์เซอร์ทั้งหมด คุณต้องใช้ VAPID (หรือคีย์เซิร์ฟเวอร์แอปพลิเคชัน) ซึ่งโดยทั่วไปต้องใช้การตั้งค่าส่วนหัวที่มีค่าเพื่อพิสูจน์ว่าแอปพลิเคชันของคุณส่งข้อความถึงผู้ใช้ได้ หากต้องการส่งข้อมูลด้วยข้อความพุช ข้อมูลจะต้องเข้ารหัสและต้องเพิ่มส่วนหัวที่เฉพาะเจาะจงเพื่อให้เบราว์เซอร์ถอดรหัสข้อความได้อย่างถูกต้อง
ปัญหาหลักในการทริกเกอร์พุชคือหากคุณพบปัญหา จะยากที่จะวิเคราะห์ปัญหา สิ่งนี้มีประสิทธิภาพมากขึ้นเมื่อเวลาผ่านไปและการรองรับเบราว์เซอร์ที่กว้างขึ้น แต่ก็ไม่ใช่เรื่องง่าย ด้วยเหตุนี้ เราจึงขอแนะนำอย่างยิ่งให้ใช้ไลบรารีในการจัดการการเข้ารหัส การจัดรูปแบบ และการทริกเกอร์ข้อความพุชของคุณ
หากคุณต้องการทราบจริงๆ ว่าห้องสมุดกำลังทำอะไร เราจะพูดถึงเรื่องนี้ในส่วนถัดไป ในตอนนี้ เราจะมาดูเรื่องการจัดการการสมัครใช้บริการและการใช้ไลบรารีพุชจากเว็บที่มีอยู่เพื่อสร้างคําขอพุช
ในส่วนนี้ เราจะใช้ไลบรารี Web-push Node ภาษาอื่นๆ จะมีความแตกต่างกัน แต่ไม่แตกต่างกันมากนัก เราพิจารณาที่ Node เนื่องจากเป็น JavaScript และผู้อ่านควรเข้าถึงโหนดได้มากที่สุด
เราจะแนะนำขั้นตอนต่อไปนี้
- ส่งการสมัครใช้บริการไปยังแบ็กเอนด์ของเราแล้วบันทึก
- ดึงข้อมูลการสมัครใช้บริการที่บันทึกไว้และเรียกให้แสดงข้อความพุช
กำลังบันทึกการสมัครใช้บริการ
การบันทึกและการค้นหา PushSubscription
จากฐานข้อมูลจะแตกต่างกันไปตามภาษาฝั่งเซิร์ฟเวอร์และตัวเลือกฐานข้อมูล แต่อาจมีประโยชน์ในการดูตัวอย่างว่าควรทำอย่างไร
ในหน้าเว็บสาธิต ระบบจะส่ง PushSubscription
ไปยังแบ็กเอนด์ของเราโดยส่งคำขอ POST ง่ายๆ ดังนี้
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.');
}
});
}
เซิร์ฟเวอร์ Express ในการสาธิตมี Listener คำขอที่ตรงกันสำหรับปลายทาง /api/save-subscription/
ดังนี้
app.post('/api/save-subscription/', function (req, res) {
ด้วยวิธีนี้ เราจะตรวจสอบการสมัครรับข้อมูลเพียงเพื่อให้มั่นใจว่าคำขอนั้นเรียบร้อยดีและไม่เต็มไปด้วยขยะ:
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;
};
หากการสมัครใช้บริการถูกต้อง เราต้องบันทึกและส่งคืนการตอบกลับ JSON ที่เหมาะสม ดังนี้
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.',
},
}),
);
});
การสาธิตนี้ใช้ nedb ในการจัดเก็บการสมัครรับข้อมูล เป็นฐานข้อมูลที่อิงตามไฟล์ที่เรียบง่าย แต่คุณสามารถใช้ฐานข้อมูลใดก็ได้ตามต้องการ เราใช้แค่นี้เพราะ ไม่ต้องตั้งค่าอะไรเลย สำหรับเวอร์ชันที่ใช้งานจริง คุณอาจจะอยากใช้วิดีโอที่น่าเชื่อถือมากกว่านี้ (ผมมักจะใช้ MySQL รุ่นเก่าๆ แบบเดิม)
function saveSubscriptionToDatabase(subscription) {
return new Promise(function (resolve, reject) {
db.insert(subscription, function (err, newDoc) {
if (err) {
reject(err);
return;
}
resolve(newDoc._id);
});
});
}
การส่งข้อความพุช
เมื่อเป็นเรื่องของการส่งข้อความพุช ท้ายที่สุดแล้ว เราจำเป็นต้องมีเหตุการณ์บางอย่างเพื่อทริกเกอร์กระบวนการส่งข้อความถึงผู้ใช้ วิธีที่ใช้กันโดยทั่วไปคือการสร้างหน้าผู้ดูแลระบบซึ่งช่วยให้คุณกำหนดค่าและทริกเกอร์ข้อความพุชได้ แต่คุณจะสร้างโปรแกรมให้ทำงานภายในเครื่องหรือวิธีการอื่นๆ ที่อนุญาตการเข้าถึงรายการของ PushSubscription
และการเรียกใช้โค้ดเพื่อทริกเกอร์ข้อความ Push ได้
การสาธิตของเรามีหน้า "คล้ายผู้ดูแลระบบ" ที่ช่วยให้คุณกระตุ้นความสนใจ เนื่องจากเป็นเพียงการสาธิต ว่าเป็นหน้าเว็บสาธารณะ
ผมจะอธิบายแต่ละขั้นตอนที่เกี่ยวข้องกับการทำให้เดโมทำงานได้ นี่จะเป็นขั้นตอนเล็กๆ ที่ทุกคน สามารถทำตามได้ รวมถึงใครก็ตามที่เพิ่งเริ่มใช้โหนดด้วย
เมื่อพูดถึงการสมัครรับข้อมูลของผู้ใช้ เราได้พูดถึงการเพิ่ม applicationServerKey
ไปยังตัวเลือก subscribe()
ซึ่งจะอยู่ในเบื้องหลังว่าเราจะต้องมีคีย์ส่วนตัวนี้
ในการสาธิต จะมีการเพิ่มค่าเหล่านี้ลงในแอปโหนด (เช่น โค้ดน่าเบื่อนะ แต่เราแค่อยากให้คุณรู้ว่าไม่มีอะไรเวทมนตร์ใดๆ)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
ถัดไปเราต้องติดตั้งโมดูล web-push
สำหรับเซิร์ฟเวอร์โหนด
npm install web-push --save
จากนั้นในสคริปต์โหนดของเรา เราต้องใช้โมดูล web-push
ดังนี้
const webpush = require('web-push');
ตอนนี้เราสามารถเริ่มใช้โมดูล web-push
ได้แล้ว ก่อนอื่น เราต้องแจ้งโมดูล web-push
เกี่ยวกับคีย์เซิร์ฟเวอร์แอปพลิเคชัน (อย่าลืมว่าคีย์เหล่านี้เรียกอีกอย่างหนึ่งว่าคีย์ VAPID เพราะนั่นคือชื่อของข้อกำหนด)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
โปรดทราบว่าเราใส่สตริง "mailto:" ไว้ด้วย สตริงนี้ต้องเป็น URL หรืออีเมล mailto อันที่จริงข้อมูลส่วนนี้จะส่งไปยังบริการพุชจากเว็บโดยเป็นส่วนหนึ่งของคำขอเพื่อทริกเกอร์พุช เหตุผลที่มีการดำเนินการเช่นนี้ก็คือ ถ้าบริการพุชจากเว็บจำเป็นต้องติดต่อผู้ส่ง ก็จะมีข้อมูลบางอย่างที่สามารถส่งให้ผู้ส่งได้
การทำเช่นนี้ทำให้โมดูล web-push
พร้อมใช้งาน ขั้นตอนต่อไปคือการเรียกข้อความพุช
เดโมใช้แผงผู้ดูแลระบบสมมติเพื่อเรียกข้อความพุช
![ภาพหน้าจอของหน้าผู้ดูแลระบบ](https://web.dev/static/articles/sending-messages-with-web-push-libraries/image/screenshot-the-admin-pag-7bb2e26069ffc.png?authuser=5&hl=th)
การคลิกปุ่ม "ทริกเกอร์ข้อความพุช" จะสร้างคำขอ POST ไปยัง /api/trigger-push-msg/
ซึ่งเป็นสัญญาณให้แบ็กเอนด์ของเราส่งข้อความพุช เราจึงสร้างเส้นทางแบบเร่งด่วนสำหรับปลายทางนี้
app.post('/api/trigger-push-msg/', function (req, res) {
เมื่อได้รับคำขอนี้ เราจะดึงข้อมูลการสมัครใช้บริการจากฐานข้อมูลและทริกเกอร์ข้อความพุชสำหรับแต่ละรายการ
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()
จะใช้ไลบรารี Web-push เพื่อส่งข้อความไปยังการสมัครใช้บริการที่ระบุได้
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()
จะส่งคืนคำสัญญา ถ้าข้อความส่งสำเร็จแล้ว สัญญาจะได้รับการแก้ไขและเราไม่ต้องดำเนินการใดๆ หากคำมั่นสัญญาถูกปฏิเสธ คุณจะต้องตรวจสอบข้อผิดพลาดซึ่งจะแจ้งให้คุณทราบว่า PushSubscription
ยังใช้งานได้อยู่หรือไม่
หากต้องการระบุประเภทข้อผิดพลาดจากบริการพุช วิธีที่ดีที่สุดคือดูที่รหัสสถานะ ข้อความแสดงข้อผิดพลาดจะแตกต่างกันไปในแต่ละบริการพุช และบางบริการอาจมีประโยชน์มากกว่าข้อความอื่นๆ
ในตัวอย่างนี้ โปรแกรมจะตรวจสอบรหัสสถานะ 404
และ 410
ซึ่งเป็นรหัสสถานะ HTTP สำหรับ "ไม่พบ" และ "ไม่มีอยู่" หากเราได้รับการแจ้งเตือนดังกล่าว แสดงว่าการสมัครใช้บริการหมดอายุหรือใช้ไม่ได้อีกต่อไป ในสถานการณ์เช่นนี้ เราจำเป็นต้องนำการสมัครใช้บริการออกจากฐานข้อมูล
ในกรณีที่มีข้อผิดพลาดอื่นๆ เราเพียงแค่ throw err
ซึ่งจะทำให้สัญญากลับมาโดย triggerPushMsg()
ถูกปฏิเสธ
เราจะอธิบายรหัสสถานะอื่นๆ บางส่วนในส่วนถัดไปเมื่อเราดูรายละเอียดเพิ่มเติมเกี่ยวกับโปรโตคอลการพุชจากเว็บ
หลังจากวนซ้ำการสมัครใช้บริการแล้ว เราต้องส่งคืนการตอบสนอง 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}'`
}
}));
});
เราได้พูดถึงขั้นตอนสำคัญในการติดตั้งใช้งาน ดังนี้
- สร้าง API เพื่อส่งการสมัครรับข้อมูลจากหน้าเว็บของเราไปยังแบ็กเอนด์ของเรา เพื่อให้บันทึกการสมัครรับข้อมูลไว้ในฐานข้อมูลได้
- สร้าง API เพื่อทริกเกอร์การส่งข้อความพุช (ในกรณีนี้คือ API ที่เรียกจากแผงการดูแลระบบที่ปลอมแปลงขึ้น)
- เรียกข้อมูลการสมัครใช้บริการทั้งหมดจากแบ็กเอนด์ของเราและส่งข้อความไปยังการสมัครใช้บริการแต่ละรายการด้วยไลบรารี Web-push
ไม่ว่าแบ็กเอนด์ของคุณจะเป็นแบบใดก็ตาม (โหนด, PHP, Python, ...) ขั้นตอนการติดตั้งใช้งานการพุชจะเหมือนกัน
ต่อไป ไลบรารีการพุชจากเว็บเหล่านี้ทำอะไรให้เราบ้าง
ขั้นตอนถัดไป
- ภาพรวมข้อความ Push ในเว็บ
- วิธีการทำงานของ Push
- การสมัครใช้บริการ
- UX ของสิทธิ์
- การส่งข้อความด้วยไลบรารีพุชจากเว็บ
- โปรโตคอลพุชจากเว็บ
- การจัดการเหตุการณ์พุช
- การแสดงการแจ้งเตือน
- ลักษณะการทำงานของการแจ้งเตือน
- รูปแบบการแจ้งเตือนทั่วไป
- คำถามที่พบบ่อยเกี่ยวกับข้อความ Push
- ปัญหาที่พบได้ทั่วไปและการรายงานข้อบกพร่อง