เมื่อ Chrome รองรับ Web Push API เป็นครั้งแรก บริการดังกล่าวอาศัยบริการ Push ของ Firebase Cloud Messaging (FCM) ซึ่งเดิมเรียกว่า Google Cloud Messaging (GCM) ซึ่งต้องใช้ API ที่เป็นกรรมสิทธิ์ ซึ่งทำให้ Chrome ให้บริการ Web Push API แก่นักพัฒนาซอฟต์แวร์ได้ในขณะที่ข้อกำหนดของ Web Push Protocol ยังคงอยู่ระหว่างการเขียน และให้บริการการตรวจสอบสิทธิ์ (หมายความว่าผู้ส่งข้อความเป็นบุคคลที่อ้างว่าเป็น) ในภายหลังเมื่อ Web Push Protocol ไม่มีการตรวจสอบสิทธิ์ ข่าวดีคือทั้ง 2 ข้อนี้ไม่เป็นความจริงแล้ว อีกต่อไป
ตอนนี้ FCM / GCM และ Chrome รองรับโปรโตคอล Web Push มาตรฐานแล้ว ขณะที่การตรวจสอบสิทธิ์ของผู้ส่งทำได้ด้วยการใช้ VAPID ซึ่งหมายความว่าเว็บแอปของคุณไม่จําเป็นต้องใช้ "gcm_sender_id" อีกต่อไป
ในบทความนี้ เราจะอธิบายวิธีแปลงโค้ดเซิร์ฟเวอร์ที่มีอยู่เพื่อใช้ Web Push Protocol กับ FCM ก่อน ถัดไป เราจะแสดงวิธีติดตั้งใช้งาน VAPID ทั้งบนโค้ดไคลเอ็นต์และเซิร์ฟเวอร์
FCM รองรับโปรโตคอล Web Push
เรามาเริ่มกันด้วยบริบทเล็กน้อย เมื่อเว็บแอปพลิเคชันลงทะเบียนเพื่อสมัครใช้บริการ Push ระบบจะกำหนด URL ของบริการ Push ให้กับแอปพลิเคชัน เซิร์ฟเวอร์จะใช้ปลายทางนี้เพื่อส่งข้อมูลไปยังผู้ใช้ผ่านเว็บแอปของคุณ ใน Chrome คุณจะได้รับปลายทาง FCM หากสมัครใช้บริการผู้ใช้โดยไม่มี VAPID (เราจะพูดถึง VAPID กันทีหลัง) ก่อนที่ FCM จะรองรับโปรโตคอล Web Push คุณต้องดึงรหัสลงทะเบียน FCM จากส่วนท้ายของ URL และใส่ไว้ในส่วนหัวก่อนส่งคําขอ FCM API ตัวอย่างเช่น ปลายทาง FCM ของ https://android.googleapis.com/gcm/send/ABCD1234
จะมีรหัสการลงทะเบียนเป็น "ABCD1234"
ตอนนี้ FCM รองรับ Web Push Protocol แล้ว คุณจึงไม่ต้องเปลี่ยนแปลงปลายทางและสามารถใช้ URL เป็นปลายทางของ Web Push Protocol ได้ (การดำเนินการนี้จะช่วยให้สอดคล้องกับ Firefox และหวังว่าเบราว์เซอร์อื่นๆ ในอนาคตทั้งหมดจะดำเนินการเช่นเดียวกัน)
ก่อนที่จะเจาะลึกเรื่อง VAPID เราต้องตรวจสอบว่าโค้ดเซิร์ฟเวอร์ของเราจัดการปลายทาง FCM อย่างถูกต้อง ด้านล่างเป็นตัวอย่างการส่งคําขอไปยังบริการ Push ใน Node โปรดทราบว่าสําหรับ FCM เราจะเพิ่มคีย์ API ลงในส่วนหัวของคําขอ สำหรับปลายทางบริการ Push อื่นๆ คุณจะไม่ต้องดำเนินการนี้ สําหรับ Chrome ก่อนเวอร์ชัน 52, Opera Android และ Samsung Browser คุณยังคงต้องใส่ "gcm_sender_id" ในไฟล์ manifest.json ของเว็บแอปด้วย ระบบจะใช้คีย์ API และรหัสผู้ส่งเพื่อตรวจสอบว่าเซิร์ฟเวอร์ที่ส่งคำขอได้รับอนุญาตให้ส่งข้อความไปยังผู้ใช้ฝั่งที่รับจริงๆ หรือไม่
const headers = new Headers();
// 12-hour notification time to live.
headers.append('TTL', 12 * 60 * 60);
// Assuming no data is going to be sent
headers.append('Content-Length', 0);
// Assuming you're not using VAPID (read on), this
// proprietary header is needed
if(subscription.endpoint
.indexOf('https://android.googleapis.com/gcm/send/') === 0) {
headers.append('Authorization', 'GCM_API_KEY');
}
fetch(subscription.endpoint, {
method: 'POST',
headers: headers
})
.then(response => {
if (response.status !== 201) {
throw new Error('Unable to send push message');
}
});
โปรดทราบว่านี่คือการเปลี่ยนแปลง API ของ FCM / GCM คุณจึงไม่จำเป็นต้องอัปเดตการสมัครใช้บริการ เพียงเปลี่ยนโค้ดเซิร์ฟเวอร์เพื่อกำหนดส่วนหัวตามที่แสดงด้านบน
ขอแนะนํา VAPID สําหรับการระบุเซิร์ฟเวอร์
VAPID คือชื่อย่อใหม่สุดเท่สำหรับ "Voluntary Application Server Identification" ข้อกำหนดใหม่นี้กำหนดการจับมือกันระหว่างเซิร์ฟเวอร์แอปกับบริการ Push และอนุญาตให้บริการ Push ยืนยันได้ว่าเว็บไซต์ใดส่งข้อความ
VAPID ช่วยให้คุณไม่ต้องทำตามขั้นตอนเฉพาะของ FCM ในการส่งข้อความ Push คุณไม่จำเป็นต้องมีโปรเจ็กต์ Firebase, gcm_sender_id
หรือส่วนหัว Authorization
อีกต่อไป
กระบวนการนี้ค่อนข้างง่าย
- เซิร์ฟเวอร์แอปพลิเคชันจะสร้างคู่คีย์สาธารณะ/ส่วนตัว ระบบจะมอบคีย์สาธารณะให้กับเว็บแอปของคุณ
- เมื่อผู้ใช้เลือกรับข้อความ Push ให้เพิ่มคีย์สาธารณะลงในออบเจ็กต์ options ของคอล subscribe()
- เมื่อเซิร์ฟเวอร์แอปส่งข้อความ Push ให้ใส่โทเค็นเว็บ JSON ที่ลงนามไว้พร้อมกับคีย์สาธารณะ
มาดูรายละเอียดของขั้นตอนเหล่านี้กัน
สร้างคู่คีย์สาธารณะ/ส่วนตัว
เราไม่ค่อยถนัดเรื่องการเข้ารหัส เราจึงขอยกตัวอย่างส่วนที่เกี่ยวข้องจากข้อกำหนดเกี่ยวกับรูปแบบของคีย์สาธารณะ/ส่วนตัว VAPID ดังนี้
เซิร์ฟเวอร์แอปพลิเคชันควรสร้างและดูแลคู่คีย์การรับรองที่ใช้ได้กับลายเซ็นดิจิทัลแบบรูปไข่ (ECDSA) บนเส้นโค้ง P-256
คุณดูวิธีการดำเนินการนี้ได้ในไลบรารีโหนด Web Push
function generateVAPIDKeys() {
var curve = crypto.createECDH('prime256v1');
curve.generateKeys();
return {
publicKey: curve.getPublicKey(),
privateKey: curve.getPrivateKey(),
};
}
การสมัครใช้บริการด้วยคีย์สาธารณะ
หากต้องการสมัครใช้บริการ Push ของผู้ใช้ Chrome ด้วยคีย์สาธารณะ VAPID คุณต้องส่งคีย์สาธารณะเป็น Uint8Array โดยใช้พารามิเตอร์ applicationServerKey
ของเมธอด subscribe()
const publicKey = new Uint8Array([0x4, 0x37, 0x77, 0xfe, …. ]);
serviceWorkerRegistration.pushManager.subscribe(
{
userVisibleOnly: true,
applicationServerKey: publicKey
}
);
คุณจะทราบว่าการดําเนินการได้ผลหรือไม่โดยตรวจสอบปลายทางในออบเจ็กต์การสมัครใช้บริการที่ได้ หากต้นทางคือ fcm.googleapis.com
แสดงว่าดําเนินการได้ผล
https://fcm.googleapis.com/fcm/send/ABCD1234
การส่งข้อความ Push
หากต้องการส่งข้อความโดยใช้ VAPID คุณต้องส่งคําขอ Web Push Protocol ปกติซึ่งมีส่วนหัว HTTP เพิ่มเติม 2 รายการ ได้แก่ ส่วนหัวการให้สิทธิ์และส่วนหัวคีย์การเข้ารหัส
ส่วนหัวการให้สิทธิ์
ส่วนหัว Authorization
คือ JSON Web Token (JWT) ที่ลงนามแล้ว โดยมี "WebPush" อยู่ด้านหน้า
JWT เป็นวิธีแชร์ออบเจ็กต์ JSON กับบุคคลที่ 2 ในลักษณะที่ฝ่ายที่ส่งสามารถลงนามได้ และฝ่ายที่รับสามารถยืนยันลายเซ็นว่ามาจากผู้ส่งที่คาดไว้ โครงสร้างของ JWT คือสตริงที่เข้ารหัส 3 รายการที่เชื่อมต่อกันด้วยจุดเดียว
<JWTHeader>.<Payload>.<Signature>
ส่วนหัว JWT
ส่วนหัว JWT มีชื่ออัลกอริทึมที่ใช้ในการลงนามและประเภทของโทเค็น สำหรับ VAPID ค่านี้ต้องเป็น
{
"typ": "JWT",
"alg": "ES256"
}
จากนั้นจะเข้ารหัส Base64 URL และกลายเป็นส่วนแรกของ JWT
เพย์โหลด
เพย์โหลดคือออบเจ็กต์ JSON อีกรายการหนึ่งที่มีข้อมูลต่อไปนี้
- กลุ่มเป้าหมาย ("aud")
- นี่คือต้นทางของบริการ Push (ไม่ใช่ต้นทางของเว็บไซต์)
ใน JavaScript คุณอาจทําดังนี้เพื่อรับกลุ่มเป้าหมาย
const audience = new URL(subscription.endpoint).origin
- นี่คือต้นทางของบริการ Push (ไม่ใช่ต้นทางของเว็บไซต์)
ใน JavaScript คุณอาจทําดังนี้เพื่อรับกลุ่มเป้าหมาย
- เวลาหมดอายุ ("exp")
- นี่คือจำนวนวินาทีก่อนที่ระบบจะถือว่าคำขอหมดอายุ การดำเนินการนี้ต้องอยู่ภายใน 24 ชั่วโมงนับจากวันที่ส่งคำขอ โดยเป็นเวลาตามเขตเวลา UTC
- เรื่อง ("sub")
- เรื่องต้องเป็น URL หรือ
mailto:
URL ซึ่งจะเป็นจุดติดต่อในกรณีที่บริการ Push ต้องการติดต่อผู้ส่งข้อความ
- เรื่องต้องเป็น URL หรือ
ตัวอย่างเพย์โหลดอาจมีลักษณะดังนี้
{
"aud": "http://push-service.example.com",
"exp": Math.floor((Date.now() / 1000) + (12 * 60 * 60)),
"sub": "mailto: my-email@some-url.com"
}
ออบเจ็กต์ JSON นี้เข้ารหัส Base64 URL และเป็นส่วนที่ 2 ของ JWT
ลายเซ็น
ลายเซ็นคือผลลัพธ์ของการรวมส่วนหัวที่เข้ารหัสและเพย์โหลดด้วยจุด แล้วเข้ารหัสผลลัพธ์โดยใช้คีย์ส่วนตัว VAPID ที่คุณสร้างไว้ก่อนหน้านี้ ผลลัพธ์ควรต่อท้ายส่วนหัวด้วยจุด
เราจะไม่แสดงตัวอย่างโค้ดสำหรับการดำเนินการนี้ เนื่องจากมีไลบรารีจํานวนมากที่จะนําส่วนหัวและเพย์โหลดออบเจ็กต์ JSON มาสร้างลายเซ็นนี้ให้คุณ
ระบบจะใช้ JWT ที่ลงชื่อเป็นส่วนหัวการให้สิทธิ์โดยใส่ "WebPush" ไว้ข้างหน้า และจะมีลักษณะดังต่อไปนี้
WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2ZjbS5nb29nbGVhcGlzLmNvbSIsImV4cCI6MTQ2NjY2ODU5NCwic3ViIjoibWFpbHRvOnNpbXBsZS1wdXNoLWRlbW9AZ2F1bnRmYWNlLmNvLnVrIn0.Ec0VR8dtf5qb8Fb5Wk91br-evfho9sZT6jBRuQwxVMFyK5S8bhOjk8kuxvilLqTBmDXJM5l3uVrVOQirSsjq0A
โปรดสังเกตสิ่งต่อไปนี้เกี่ยวกับเรื่องนี้ ประการแรก ส่วนหัวการให้สิทธิ์ต้องมีคำว่า "WebPush" และตามด้วยเว้นวรรคแล้วตามด้วย JWT และสังเกตจุดคั่นระหว่างส่วนหัว JWT, เพย์โหลด และลายเซ็น
ส่วนหัวคีย์การเข้ารหัส
นอกจากส่วนหัวการให้สิทธิ์แล้ว คุณต้องเพิ่มคีย์สาธารณะ VAPID ลงในส่วนหัว Crypto-Key
เป็นสตริงที่เข้ารหัส Base64 URL โดยใส่ p256ecdsa=
ไว้ข้างหน้า
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaNndIo
เมื่อส่งการแจ้งเตือนที่มีข้อมูลที่เข้ารหัส คุณจะใช้ส่วนหัว Crypto-Key
อยู่แล้ว ดังนั้นหากต้องการเพิ่มคีย์เซิร์ฟเวอร์แอปพลิเคชัน คุณเพียงแค่เพิ่มเซมิโคลอนก่อนเพิ่มเนื้อหาข้างต้น ผลลัพธ์ที่ได้จะเป็นดังนี้
dh=BGEw2wsHgLwzerjvnMTkbKrFRxdmwJ5S_k7zi7A1coR_sVjHmGrlvzYpAT1n4NPbioFlQkIrTNL8EH4V3ZZ4vJE;
p256ecdsa=BDd3_hVL9fZi9Ybo2UUzA284WG5FZR30_95YeZJsiApwXKpNcF1rRPF3foIiBHXRdJI2Qhumhf6_LFTeZaN
ความเป็นจริงของการเปลี่ยนแปลงเหล่านี้
เมื่อใช้ VAPID คุณไม่จำเป็นต้องลงชื่อสมัครใช้บัญชีกับ GCM เพื่อใช้ Push ใน Chrome อีกต่อไป และสามารถใช้เส้นทางโค้ดเดียวกันสำหรับการติดตามผู้ใช้และส่งข้อความถึงผู้ใช้ทั้งใน Chrome และ Firefox ทั้ง 2 รายการเป็นไปตามมาตรฐาน
สิ่งที่ควรทราบคือใน Chrome 51 และเวอร์ชันก่อนหน้า, Opera สำหรับ Android และเบราว์เซอร์ Samsung คุณยังคงต้องกำหนด gcm_sender_id
ในไฟล์ Manifest ของเว็บแอป และจะต้องเพิ่มส่วนหัวการอนุญาตไปยังปลายทาง FCM ที่ระบบจะแสดงผล
VAPID เป็นทางเลือกที่ไม่ต้องปฏิบัติตามข้อกำหนดที่เป็นกรรมสิทธิ์เหล่านี้ หากใช้ VAPID ระบบจะทํางานในเบราว์เซอร์ทั้งหมดที่รองรับ Web Push เมื่อเบราว์เซอร์รองรับ VAPID มากขึ้น คุณสามารถเลือกได้ว่าจะนำ gcm_sender_id
ออกจากไฟล์ Manifest เมื่อใด