ในตอนที่ Chrome รองรับ Web Push API เป็นครั้งแรก Chrome จะใช้บริการพุชใน 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 Protocol คุณต้องดึงรหัสการลงทะเบียน FCM จากส่วนท้าย URL และใส่ไว้ในส่วนหัวก่อนที่จะส่งคำขอ API ของ FCM ตัวอย่างเช่น ปลายทาง FCM ของ https://android.googleapis.com/gcm/send/ABCD1234
จะมีรหัสการลงทะเบียนเป็น "ABCD1234"
เนื่องจาก FCM รองรับโปรโตคอล Web Push แล้ว คุณจึงปล่อยให้ปลายทางไม่เปลี่ยนแปลงตามเดิมและใช้ 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 สำหรับการส่งข้อความพุชได้ คุณไม่จำเป็นต้องมีโปรเจ็กต์ Firebase, gcm_sender_id
หรือส่วนหัว Authorization
อีกต่อไป
กระบวนการนี้ค่อนข้างง่าย:
- เซิร์ฟเวอร์แอปพลิเคชันจะสร้างคู่คีย์สาธารณะ/ส่วนตัว ระบบจะมอบคีย์สาธารณะให้กับเว็บแอปของคุณ
- เมื่อผู้ใช้เลือกรับพุช ให้เพิ่มคีย์สาธารณะไปยังออบเจ็กต์ตัวเลือกของการเรียกใช้ subscription()
- เมื่อเซิร์ฟเวอร์แอปส่งข้อความพุช ให้ใส่โทเค็นเว็บ 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"
}
จากนั้นจะเข้ารหัส URL base64 และเป็นส่วนแรกของ JWT
เพย์โหลด
เพย์โหลดคือออบเจ็กต์ JSON อีกรายการหนึ่งที่มีข้อมูลต่อไปนี้
- ผู้ชม ("aud")
- นี่คือต้นทางของบริการ Push (ไม่ใช่ต้นทางของเว็บไซต์)
ใน JavaScript คุณสามารถดึงข้อมูลกลุ่มเป้าหมายได้โดยทําดังนี้
const audience = new URL(subscription.endpoint).origin
- นี่คือต้นทางของบริการ Push (ไม่ใช่ต้นทางของเว็บไซต์)
ใน JavaScript คุณสามารถดึงข้อมูลกลุ่มเป้าหมายได้โดยทําดังนี้
- เวลาหมดอายุ ("exp")
- นี่คือจำนวนวินาทีที่ควรถือว่าคำขอหมดอายุ การดำเนินการนี้ต้องอยู่ภายใน 24 ชั่วโมงนับจากวันที่ส่งคำขอ โดยเป็นเวลาตามเขตเวลา UTC
- เรื่อง ("sub")
- เรื่องต้องเป็น URL หรือ URL ของ
mailto:
ซึ่งจะเป็นจุดติดต่อในกรณีที่บริการ Push ต้องการติดต่อผู้ส่งข้อความ
- เรื่องต้องเป็น URL หรือ 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 จะใช้ได้กับทุกเบราว์เซอร์ที่รองรับการพุชจากเว็บ เมื่อเบราว์เซอร์รองรับ VAPID มากขึ้น คุณสามารถเลือกได้ว่าจะนำ gcm_sender_id
ออกจากไฟล์ Manifest เมื่อใด