Để gửi thông báo đẩy, trước tiên, bạn phải được người dùng cho phép rồi đăng ký thiết bị của họ vào một dịch vụ đẩy. Việc này liên quan đến việc sử dụng API JavaScript để lấy một đối tượng PushSubscription, sau đó bạn sẽ gửi đối tượng này đến máy chủ của mình.
JavaScript API quản lý quy trình này một cách đơn giản. Hướng dẫn này giải thích toàn bộ quy trình, bao gồm cả việc phát hiện tính năng, yêu cầu cấp quyền và quản lý quy trình đăng ký.
Phát hiện đối tượng
Trước tiên, hãy kiểm tra xem trình duyệt có hỗ trợ thông báo đẩy hay không. Bạn có thể kiểm tra xem có hỗ trợ thông báo đẩy hay không bằng 2 bước kiểm tra:
- Kiểm tra
serviceWorkertrên đối tượngnavigator. - Kiểm tra
PushManagertrên đối tượngwindow.
if (!('serviceWorker' in navigator)) {
// Service Worker isn't supported on this browser, disable or hide UI.
return;
}
if (!('PushManager' in window)) {
// Push isn't supported on this browser, disable or hide UI.
return;
}
Mặc dù trình duyệt ngày càng hỗ trợ cả worker dịch vụ và thông báo đẩy, nhưng bạn nên luôn phát hiện cả hai tính năng này và tăng cường ứng dụng của mình một cách liên tục.
Đăng ký trình chạy dịch vụ
Sau khi phát hiện tính năng, bạn biết rằng service worker và thông báo đẩy được hỗ trợ. Tiếp theo, hãy đăng ký trình chạy dịch vụ.
Khi đăng ký một worker dịch vụ, bạn sẽ cho trình duyệt biết vị trí của tệp worker dịch vụ. Tệp này là một tệp JavaScript, nhưng trình duyệt cấp cho tệp này quyền truy cập vào các API của worker dịch vụ, bao gồm cả tính năng nhắn tin đẩy. Cụ thể, trình duyệt sẽ chạy tệp trong môi trường worker dịch vụ.
Để đăng ký một worker dịch vụ, hãy gọi navigator.serviceWorker.register() và truyền đường dẫn đến tệp của bạn. Ví dụ:
function registerServiceWorker() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
console.log('Service worker successfully registered.');
return registration;
})
.catch(function (err) {
console.error('Unable to register service worker.', err);
});
}
Hàm này cho trình duyệt biết vị trí của tệp worker dịch vụ. Ở đây, tệp trình chạy dịch vụ nằm ở /service-worker.js. Sau khi bạn gọi register(), trình duyệt sẽ thực hiện các bước sau:
Tải tệp worker dịch vụ xuống.
Chạy JavaScript.
Nếu tệp chạy đúng cách mà không có lỗi, thì lời hứa do
register()trả về sẽ được giải quyết. Nếu xảy ra lỗi, lời hứa sẽ bị từ chối.
Lưu ý: Nếu register() từ chối, hãy kiểm tra JavaScript để tìm lỗi chính tả hoặc lỗi trong Công cụ của Chrome cho nhà phát triển.
Khi register() phân giải, nó sẽ trả về một ServiceWorkerRegistration. Bạn sử dụng thông tin đăng ký này để truy cập vào PushManager API.
Khả năng tương thích của trình duyệt PushManager API
Yêu cầu cấp quyền
Sau khi đăng ký service worker và có được quyền, hãy xin phép người dùng để gửi thông báo đẩy.
API để nhận quyền rất đơn giản. Tuy nhiên, gần đây, API đã thay đổi từ việc lấy một lệnh gọi lại sang trả về một Lời hứa. Vì không thể xác định phiên bản API mà trình duyệt triển khai, nên bạn phải triển khai và xử lý cả hai phiên bản.
function askPermission() {
return new Promise(function (resolve, reject) {
const permissionResult = Notification.requestPermission(function (result) {
resolve(result);
});
if (permissionResult) {
permissionResult.then(resolve, reject);
}
}).then(function (permissionResult) {
if (permissionResult !== 'granted') {
throw new Error("We weren't granted permission.");
}
});
}
Trong mã trước đó, lệnh gọi đến Notification.requestPermission() sẽ hiển thị một lời nhắc cho người dùng:

Sau khi người dùng tương tác với lời nhắc về quyền bằng cách chọn Cho phép, Chặn hoặc đóng lời nhắc, bạn sẽ nhận được kết quả dưới dạng một chuỗi: 'granted', 'default' hoặc 'denied'.
Trong mã mẫu, lời hứa do askPermission() trả về sẽ phân giải nếu quyền được cấp; nếu không, lời hứa sẽ đưa ra lỗi và từ chối.
Xử lý trường hợp đặc biệt khi người dùng nhấp vào nút Chặn. Nếu điều này xảy ra, ứng dụng web của bạn sẽ không thể yêu cầu người dùng cấp quyền nữa. Người dùng phải bỏ chặn ứng dụng của bạn theo cách thủ công bằng cách thay đổi trạng thái quyền của ứng dụng trong một bảng cài đặt. Hãy cân nhắc kỹ thời điểm và cách yêu cầu cấp quyền, vì nếu người dùng nhấp vào Chặn, họ sẽ khó có thể thay đổi quyết định đó.
Hầu hết người dùng đều cấp quyền nếu họ hiểu lý do ứng dụng yêu cầu quyền đó.
Tài liệu này thảo luận về cách một số trang web phổ biến yêu cầu cấp quyền ở phần sau của tài liệu.
Đăng ký người dùng bằng PushManager
Sau khi đăng ký trình chạy dịch vụ và nhận được quyền, bạn có thể đăng ký cho người dùng bằng cách gọi registration.pushManager.subscribe().
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
Khi gọi phương thức subscribe(), bạn sẽ truyền một đối tượng options bao gồm các tham số bắt buộc và không bắt buộc.
Phần này mô tả các lựa chọn mà bạn có thể truyền.
các lựa chọn userVisibleOnly
Khi tính năng nhắn tin đẩy được thêm vào trình duyệt lần đầu tiên, các nhà phát triển không chắc chắn về việc gửi tin nhắn đẩy mà không hiển thị thông báo. Điều này thường được gọi là thông báo đẩy thầm lặng vì người dùng không biết rằng một sự kiện đã xảy ra ở chế độ nền.
Mối lo ngại là nhà phát triển có thể liên tục theo dõi vị trí của người dùng mà người dùng không biết.
Để tránh trường hợp này và cho phép tác giả đặc tả cân nhắc cách hỗ trợ tốt nhất cho tính năng này, chúng tôi đã thêm lựa chọn userVisibleOnly. Truyền giá trị true là một thoả thuận mang tính biểu tượng với trình duyệt rằng ứng dụng web sẽ hiển thị thông báo mỗi khi nhận được một thông báo đẩy (tức là không có thông báo đẩy thầm lặng).
Bạn phải truyền giá trị true. Nếu không thêm khoá userVisibleOnly hoặc truyền false, bạn sẽ gặp lỗi sau:
Chrome currently only supports the Push API for subscriptions that will result
in user-visible messages. You can indicate this by calling
`pushManager.subscribe({userVisibleOnly: true})` instead. See
[https://goo.gl/yqv4Q4](https://goo.gl/yqv4Q4) for more details.
Chrome chỉ hỗ trợ Push API cho những lượt đăng ký dẫn đến thông báo mà người dùng có thể thấy. Cho biết điều này bằng cách gọi pushManager.subscribe({userVisibleOnly: true}). Để biết thêm thông tin, hãy xem https://goo.gl/yqv4Q4.
Có vẻ như Chrome sẽ không triển khai tính năng thông báo đẩy im lặng trên diện rộng. Thay vào đó, các tác giả đặc tả đang khám phá một API ngân sách cho phép các ứng dụng web gửi một số thông báo đẩy thầm lặng dựa trên mức sử dụng ứng dụng web.
lựa chọn applicationServerKey
Trước đây, tài liệu này có đề cập đến khoá máy chủ ứng dụng. Dịch vụ truyền tin nhắn đẩy sử dụng khoá máy chủ ứng dụng để xác định ứng dụng đăng ký người dùng và đảm bảo rằng ứng dụng đó gửi tin nhắn cho người dùng.
Khoá máy chủ ứng dụng là một cặp khoá công khai và khoá riêng tư dành riêng cho ứng dụng của bạn. Hãy giữ bí mật khoá riêng tư cho ứng dụng của bạn và chia sẻ khoá công khai một cách thoải mái.
Lựa chọn applicationServerKey được truyền vào lệnh gọi subscribe() là khoá công khai của ứng dụng. Trình duyệt sẽ truyền khoá này đến một dịch vụ thông báo đẩy khi đăng ký người dùng, cho phép dịch vụ thông báo đẩy liên kết khoá công khai của ứng dụng với PushSubscription của người dùng.
Sơ đồ sau đây minh hoạ các bước này.
- Tải ứng dụng web của bạn trong một trình duyệt và gọi
subscribe(), truyền khoá máy chủ ứng dụng công khai của bạn. - Sau đó, trình duyệt sẽ gửi một yêu cầu mạng đến dịch vụ truyền tin nhắn đẩy. Dịch vụ này sẽ tạo một điểm cuối, liên kết điểm cuối này với khoá công khai của ứng dụng và trả về điểm cuối cho trình duyệt.
- Trình duyệt sẽ thêm điểm cuối này vào
PushSubscriptionmà lời hứasubscribe()trả về.
Khi bạn gửi thông báo đẩy, hãy tạo một tiêu đề Uỷ quyền chứa thông tin được ký bằng khoá riêng tư của máy chủ ứng dụng. Khi nhận được yêu cầu gửi thông báo đẩy, dịch vụ đẩy sẽ xác thực tiêu đề Uỷ quyền đã ký này bằng cách tra cứu khoá công khai được liên kết với điểm cuối nhận được yêu cầu. Nếu chữ ký hợp lệ, dịch vụ truyền dữ liệu qua push sẽ biết rằng yêu cầu đến từ máy chủ ứng dụng có khoá riêng tư trùng khớp. Đây là một biện pháp bảo mật giúp ngăn người khác gửi tin nhắn cho người dùng ứng dụng của bạn.
Về mặt kỹ thuật, applicationServerKey là không bắt buộc. Tuy nhiên, quy trình triển khai đơn giản nhất trên Chrome yêu cầu điều này và các trình duyệt khác có thể yêu cầu điều này trong tương lai. Đây là bước không bắt buộc trên Firefox.
Thông số kỹ thuật VAPID xác định khoá máy chủ ứng dụng. Khi bạn thấy các thông tin tham chiếu đến khoá máy chủ ứng dụng hoặc khoá VAPID, hãy nhớ rằng chúng là một.
Tạo khoá máy chủ ứng dụng
Bạn có thể tạo một bộ khoá máy chủ ứng dụng công khai và riêng tư bằng cách truy cập vào web-push-codelab.glitch.me hoặc bằng cách sử dụng dòng lệnh web-push để tạo khoá như sau:
$ npm install -g web-push
$ web-push generate-vapid-keys
Bạn chỉ cần tạo những khoá này một lần cho ứng dụng của mình và đảm bảo rằng bạn giữ khoá riêng tư ở chế độ riêng tư.
Quyền và subscribe()
Việc gọi subscribe() có một tác dụng phụ. Nếu ứng dụng web của bạn không có quyền hiển thị thông báo khi bạn gọi subscribe(), thì trình duyệt sẽ yêu cầu cấp quyền cho bạn. Điều này hữu ích nếu giao diện người dùng của bạn hoạt động với quy trình này, nhưng nếu bạn muốn có nhiều quyền kiểm soát hơn (điều mà hầu hết nhà phát triển đều muốn), hãy sử dụng API Notification.requestPermission() mà tài liệu này đã đề cập trước đó.
Tổng quan về PushSubscription
Bạn gọi subscribe(), truyền các lựa chọn và nhận một lời hứa sẽ phân giải thành PushSubscription. Ví dụ:
function subscribeUserToPush() {
return navigator.serviceWorker
.register('/service-worker.js')
.then(function (registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
),
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function (pushSubscription) {
console.log(
'Received PushSubscription: ',
JSON.stringify(pushSubscription),
);
return pushSubscription;
});
}
Đối tượng PushSubscription chứa tất cả thông tin cần thiết để gửi thông báo đẩy cho người dùng đó. Nếu in nội dung bằng JSON.stringify(), bạn sẽ thấy nội dung sau:
{
"endpoint": "https://some.pushservice.com/something-unique",
"keys": {
"p256dh":
"BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
"auth":"FPssNDTKnInHVndSTdbKFw=="
}
}
endpoint là URL của dịch vụ truyền dữ liệu. Để kích hoạt thông báo đẩy, hãy đưa ra yêu cầu POST đến URL này.
Đối tượng keys chứa các giá trị dùng để mã hoá dữ liệu thông báo được gửi cùng với thông báo đẩy. (Tài liệu này sẽ thảo luận về việc mã hoá thư sau.)
Gửi gói thuê bao đến máy chủ của bạn
Sau khi bạn có một gói thuê bao truyền dữ liệu, hãy gửi gói đó đến máy chủ của bạn. Bạn quyết định cách gửi dữ liệu, nhưng một mẹo là sử dụng JSON.stringify() để trích xuất tất cả dữ liệu cần thiết từ đối tượng đăng ký. Ngoài ra, bạn có thể tự tổng hợp kết quả tương tự, ví dụ:
const subscriptionObject = {
endpoint: pushSubscription.endpoint,
keys: {
p256dh: pushSubscription.getKeys('p256dh'),
auth: pushSubscription.getKeys('auth'),
},
};
// The above is the same output as:
const subscriptionObjectToo = JSON.stringify(pushSubscription);
Để gửi yêu cầu đăng ký từ trang web, hãy sử dụng nội dung sau:
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.');
}
});
}
Máy chủ Node.js nhận yêu cầu này và lưu dữ liệu vào cơ sở dữ liệu để sử dụng sau này.
app.post('/api/save-subscription/', function (req, res) {
if (!isValidSaveRequest(req, res)) {
return;
}
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.',
},
}),
);
});
});
Với thông tin chi tiết PushSubscription trên máy chủ, bạn có thể gửi tin nhắn cho người dùng bất cứ lúc nào.
Thường xuyên đăng ký lại để tránh hết hạn
Khi đăng ký nhận thông báo đẩy, bạn thường nhận được PushSubscription.expirationTime của null. Về lý thuyết, điều này có nghĩa là gói thuê bao không bao giờ hết hạn. (Ngược lại, DOMHighResTimeStamp cho biết thời gian hết hạn chính xác.) Tuy nhiên, trên thực tế, các trình duyệt thường cho phép các lượt đăng ký hết hạn. Ví dụ: điều này có thể xảy ra nếu không có thông báo đẩy nào được nhận trong một thời gian dài hoặc nếu trình duyệt phát hiện thấy người dùng không sử dụng ứng dụng có quyền gửi thông báo đẩy. Một mẫu để ngăn chặn điều này là đăng ký lại người dùng khi nhận được mỗi thông báo, như đoạn mã sau đây cho thấy. Điều này đòi hỏi bạn phải gửi thông báo đủ thường xuyên để ngăn trình duyệt tự động hết hạn đăng ký. Bạn nên cân nhắc kỹ lưỡng những ưu điểm và nhược điểm của nhu cầu thông báo chính đáng so với việc vô tình gửi thông báo rác cho người dùng chỉ để ngăn gói thuê bao hết hạn. Cuối cùng, bạn không nên tìm cách lách những nỗ lực của trình duyệt nhằm bảo vệ người dùng khỏi các lượt đăng ký nhận thông báo đã bị quên từ lâu.
/* In the Service Worker. */
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
// Display notification or handle data
// Example: show a notification
const title = 'New Notification';
const body = 'You have new updates!';
const icon = '/images/icon.png';
const tag = 'simple-push-demo-notification-tag';
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
);
// Attempt to resubscribe after receiving a notification
event.waitUntil(resubscribeToPush());
});
function resubscribeToPush() {
return self.registration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(function() {
return self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
});
})
.then(function(subscription) {
console.log('Resubscribed to push notifications:', subscription);
// Optionally, send new subscription details to your server
})
.catch(function(error) {
console.error('Failed to resubscribe:', error);
});
}
Câu hỏi thường gặp
Sau đây là một số câu hỏi thường gặp:
Bạn có thể thay đổi dịch vụ truyền dữ liệu mà trình duyệt sử dụng không?
Không, trình duyệt sẽ chọn dịch vụ truyền tin nhắn đẩy. Như đã thảo luận trong tài liệu này với lệnh gọi subscribe(), trình duyệt sẽ gửi các yêu cầu mạng đến dịch vụ truyền tin nhắn đẩy để truy xuất thông tin chi tiết tạo nên PushSubscription.
Các dịch vụ truyền dữ liệu qua push có dùng các API khác nhau không?
Tất cả các dịch vụ truyền dữ liệu đều mong đợi cùng một API.
API chung này (gọi là Web Push Protocol) mô tả yêu cầu mạng mà ứng dụng của bạn gửi để kích hoạt thông báo đẩy.
Nếu bạn đăng ký một người dùng trên máy tính, thì họ có được đăng ký trên điện thoại không?
Không. Người dùng phải đăng ký nhận thông báo đẩy trên mỗi trình duyệt mà họ muốn nhận thông báo. Người dùng cũng phải cấp quyền trên từng thiết bị.
Các bước tiếp theo
- Tổng quan về thông báo đẩy trên web
- Cách hoạt động của tính năng nhắn tin đẩy
- Đăng ký người dùng
- Trải nghiệm người dùng về quyền
- Gửi thông báo bằng thư viện thông báo đẩy trên web
- Giao thức thông báo đẩy trên web
- Xử lý sự kiện đẩy
- Hiển thị thông báo
- Cách hoạt động của thông báo
- Các mẫu thông báo thường gặp
- Câu hỏi thường gặp về thông báo đẩy
- Các vấn đề thường gặp và cách báo cáo lỗi