Đăng ký người dùng

Bước đầu tiên là xin phép người dùng gửi thông báo đẩy cho họ, sau đó chúng ta có thể thao tác trên PushSubscription.

API JavaScript để thực hiện việc này là một cách hợp lý ngay lập tức, vì vậy, hãy cùng thực hiện qua luồng logic.

Phát hiện tính năng

Trước tiên, chúng ta cần kiểm tra xem trình duyệt hiện tại có thực sự hỗ trợ thông báo đẩy hay không. Chúng ta có thể kiểm tra xem phương thức đẩy có được hỗ trợ hay không bằng 2 quy trình kiểm tra đơn giản.

  1. Kiểm tra serviceWorker trên navigation.
  2. Kiểm tra PushManager trên cửa sổ.
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ù mức độ hỗ trợ trình duyệt đang phát triển nhanh chóng cho cả trình chạy dịch vụ và thông báo đẩy, nhưng bạn luôn nên phát hiện tính năng cho cả trình chạy dịch vụ và tăng dần.

Đăng ký một trình chạy dịch vụ

Với tính năng phát hiện tính năng, chúng ta biết rằng cả trình chạy dịch vụ và Đẩy đều được hỗ trợ. Bước tiếp theo là "đăng ký" trình chạy dịch vụ của chúng ta.

Khi đăng ký một trình chạy dịch vụ, chúng ta sẽ cho trình duyệt biết vị trí của tệp trình chạy dịch vụ. Tệp vẫn chỉ là JavaScript, nhưng trình duyệt sẽ "cấp quyền truy cập" vào các API trình chạy dịch vụ, bao gồm cả thông báo đẩy. Chính xác hơn, trình duyệt chạy tệp trong môi trường trình chạy dịch vụ.

Để đăng ký một trình chạy dịch vụ, hãy gọi navigator.serviceWorker.register(), truyền vào đường dẫn đến tệp của chúng ta. Chẳng hạn như:

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 rằng chúng ta có tệp service worker và vị trí của tệp. Trong trường hợp này, tệp trình chạy dịch vụ nằm ở /service-worker.js. Sau khi gọi register(), trình duyệt sẽ thực hiện các bước sau đây:

  1. Tải tệp trình chạy dịch vụ xuống.

  2. Chạy JavaScript.

  3. Nếu mọi thứ chạy chính xác và không có lỗi, thì lời hứa do register() trả về sẽ được giải quyết. Nếu có lỗi dưới bất kỳ hình thức nào, lời hứa sẽ bị từ chối.

Nếu register() từ chối, hãy kiểm tra kỹ JavaScript để tìm lỗi chính tả / lỗi trong Công cụ của Chrome cho nhà phát triển.

Khi phân giải xong, register() sẽ trả về một ServiceWorkerRegistration. Chúng tôi sẽ sử dụng lượt đăng ký này để truy cập vào API PushManager.

Khả năng tương thích của trình duyệt API PushManager

Hỗ trợ trình duyệt

  • 42
  • 17
  • 44
  • 16

Nguồn

Yêu cầu cấp quyền

Chúng ta đã đăng ký trình chạy dịch vụ và sẵn sàng đăng ký người dùng, bước tiếp theo là nhận được sự cho phép của người dùng để gửi thông báo đẩy cho họ.

API để xin cấp quyền tương đối đơn giản, nhược điểm là API gần đây đã thay đổi từ việc thực hiện lệnh gọi lại thành trả về một Promise. Vấn đề của vấn đề này là chúng tôi không thể cho biết trình duyệt hiện tại triển khai phiên bản API nào. Vì vậy, bạn phải triển khai cả hai và xử lý cả hai.

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ên, đoạn mã quan trọng là lệnh gọi đến Notification.requestPermission(). Phương thức này sẽ hiển thị một lời nhắc cho người dùng:

Lời nhắc cấp quyền trên Chrome dành cho máy tính và thiết bị di động.

Sau khi người dùng tương tác với lời nhắc cấp quyền bằng cách nhấn Cho phép, Chặn hoặc chỉ đóng lời nhắc, chúng ta sẽ nhận được kết quả dưới dạng một chuỗi: 'granted', 'default' hoặc 'denied'.

Trong mã mẫu ở trên, lời hứa do askPermission() trả về sẽ phân giải nếu quyền được cấp, nếu không thì chúng tôi sẽ gửi ra lỗi khi từ chối lời hứa.

Một trường hợp hiếm gặp mà bạn cần xử lý là 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 lại. Họ sẽ phải "bỏ chặn" ứng dụng theo cách thủ công bằng cách thay đổi trạng thái cấp quyền của ứng dụng, trạng thái này nằm trong bảng điều khiển cài đặt. Hãy suy nghĩ kỹ về cách thức và thời điểm bạn yêu cầu người dùng cấp quyền, vì nếu họ nhấp vào chặn, đó không phải là cách dễ dàng để đảo ngược quyết định đó.

Tin vui là hầu hết người dùng đều sẵn sàng cấp quyền, miễn là họ biết lý do yêu cầu cấp quyền đó.

Chúng ta sẽ xem cách một số trang web phổ biến yêu cầu cấp quyền sau này.

Đăng ký người dùng bằng PushManager

Sau khi đăng ký trình chạy dịch vụ và được cấp quyền, chúng ta có thể đăng ký 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(), chúng ta sẽ truyền vào một đối tượng options (tuỳ chọn), bao gồm cả tham số bắt buộc và không bắt buộc.

Hãy xem tất cả các tuỳ chọn mà chúng ta có thể chuyển vào.

Tuỳ chọn userVisibleOnly

Trong lần đầu thêm thông báo đẩy vào trình duyệt, chúng tôi chưa chắc chắn về việc liệu nhà phát triển có thể gửi thông báo đẩy hay không cũng như không hiển thị thông báo. Đây thường được gọi là đẩy im lặng, do người dùng không biết rằng đã có gì đó xảy ra trong nền.

Mối lo ngại là các nhà phát triển có thể thực hiện những việc xấu như theo dõi vị trí của người dùng liên tục mà người dùng không biết.

Để tránh trường hợp này và cho tác giả thông số kỹ thuật có thời gian xem xét cách hỗ trợ tốt nhất cho tính năng này, tuỳ chọn userVisibleOnly đã được thêm và truyền giá trị true là thoả thuận tượng trư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 lệnh đẩy (tức là không đẩy im lặng).

Tại thời điểm này, bạn phải chuyển vào một giá trị true. Nếu không bao gồm khoá userVisibleOnly hoặc truyền vào false, bạn sẽ gặp lỗi sau:

Chrome hiện chỉ hỗ trợ API Push cho các gói thuê bao dẫn đến thông báo mà người dùng nhìn thấy. Bạn có thể cho biết điều này bằng cách gọi pushManager.subscribe({userVisibleOnly: true}). Hãy truy cập vào https://goo.gl/yqv4Q4 để biết thêm thông tin.

Hiện tại, có vẻ như tính năng đẩy im lặng hàng loạt sẽ không bao giờ được triển khai trong Chrome. Thay vào đó, các tác giả thông số kỹ thuật đang tìm hiểu khái niệm API ngân sách, cho phép các ứng dụng web một số lượng thông báo đẩy im lặng nhất định dựa trên mức sử dụng ứng dụng web.

Tuỳ chọn applicationServerKey

Chúng tôi đã đề cập ngắn gọn đến "khoá máy chủ ứng dụng" trong phần trước. "Khoá máy chủ ứng dụng" được một dịch vụ đẩy sử dụng để xác định ứng dụng đã đăng ký người dùng và đảm bảo rằng chính ứng dụng đó sẽ gửi thông báo cho người dùng đó.

Khoá máy chủ ứng dụng là cặp khoá công khai và riêng tư dành riêng cho ứng dụng của bạn. Khoá riêng tư phải được giữ bí mật với ứng dụng của bạn và bạn có thể chia sẻ khoá công khai một cách thoải mái.

Tuỳ 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 chuyển thông tin này sang dịch vụ đẩy khi đăng ký người dùng, nghĩa là dịch vụ đẩy có thể liên kết khoá công khai của ứng dụng với PushSubscription của người dùng.

Sơ đồ dưới đây minh hoạ các bước này.

  1. Ứng dụng web của bạn được tải trong trình duyệt và bạn gọi subscribe(), truyền khoá máy chủ ứng dụng công khai.
  2. Sau đó, trình duyệt gửi yêu cầu mạng tới một dịch vụ đẩ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 rồi trả về điểm cuối cho trình duyệt.
  3. Trình duyệt sẽ thêm điểm cuối này vào PushSubscription, điểm cuối này sẽ được trả về thông qua lời hứa subscribe().

Hình minh hoạ khoá máy chủ ứng dụng công khai được dùng trong phương thức đăng ký.

Sau này nếu muốn gửi một thông báo đẩy, bạn cần tạo tiêu đề Uỷ quyền. Tiêu đề này sẽ 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 có thể 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 yêu cầu. Nếu chữ ký hợp lệ, thì dịch vụ đẩy sẽ biết rằng chữ ký đó phải đến từ máy chủ ứng dụng có khoá riêng tư trùng khớp. Về cơ bản, đây là một biện pháp bảo mật giúp ngăn chặn bất kỳ ai khác gửi thông báo đến người dùng ứng dụng.

Cách sử dụng khoá máy chủ ứng dụng riêng tư khi gửi tin nhắn

Về mặt kỹ thuật, applicationServerKey là không bắt buộc. Tuy nhiên, cách triển khai dễ nhất trên Chrome đòi hỏi phải có kỹ thuật này và các trình duyệt khác có thể yêu cầu trong tương lai. Không bắt buộc trên Firefox.

Thông số kỹ thuật xác định khoá máy chủ ứng dụng cần phải là thông số kỹ thuật VAPID. Mỗi khi bạn đọc nội dung đề cập đến "khoá máy chủ ứng dụng" hoặc "khoá VAPID", hãy nhớ rằng chúng giống nhau.

Cách tạo khoá máy chủ ứng dụng

Bạn có thể tạo một tập hợp khoá máy chủ ứng dụng công khai và riêng tư bằng cách truy cập web-push-codelab.glitch.me hoặc bạn có thể sử dụng dòng lệnh web-push để tạo khoá bằng cách thực hiện các bước sau:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

Bạn chỉ cần tạo các khoá này một lần cho ứng dụng của mình, chỉ cần đảm bảo rằng bạn giữ riêng tư cho khoá riêng tư. (Vâng, tôi vừa nói thế.)

Quyền và gói thuê bao()

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ông báo tại thời điểm gọi subscribe(), thì trình duyệt sẽ yêu cầu cấp quyền cho bạn. Điều này sẽ 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 (và tôi cho rằng hầu hết các nhà phát triển sẽ làm như vậy), hãy sử dụng API Notification.requestPermission() mà chúng ta đã sử dụng trước đó.

PushSubscription là gì?

Chúng ta gọi subscribe(), truyền một số tuỳ chọn và đổi lại, chúng ta nhận được một lời hứa phân giải thành PushSubscription, dẫn đến một số mã như sau:

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 cần thiết để gửi thông báo đẩy đến người dùng đó. Nếu in nội dung bằng JSON.stringify(), bạn sẽ thấy những thông tin sau:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint là URL của dịch vụ đẩy. Để kích hoạt thông báo đẩy, hãy thực hiện yêu cầu POST cho 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 bằng thông báo đẩy (chúng ta sẽ thảo luận về nội dung này sau trong phần này).

Gửi gói thuê bao đến máy chủ của bạn

Sau khi có gói thuê bao đẩy, bạn cần gửi gói thuê bao đó đến máy chủ của mình. Bạn có thể tuỳ ý làm điều đó. Tuy nhiên, bạn có thể sử dụng JSON.stringify() để lấy tất cả dữ liệu cần thiết từ đối tượng gói thuê bao. Ngoài ra, bạn có thể ghép nối cùng một kết quả theo cách thủ công như sau:

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);

Bạn có thể gửi gói thuê bao trên trang web như 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ủ nút nhận được 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 về PushSubscription trên máy chủ, chúng ta có thể gửi thông báo cho người dùng bất cứ khi nào chúng ta muốn.

Câu hỏi thường gặp

Một vài câu hỏi phổ biến mà mọi người đã hỏi vào thời điểm này:

Tôi có thể thay đổi dịch vụ đẩy mà trình duyệt sử dụng không?

Không. Dịch vụ đẩy được trình duyệt chọn và như chúng ta đã thấy với lệnh gọi subscribe(), trình duyệt sẽ gửi yêu cầu mạng đến dịch vụ đẩy để truy xuất thông tin chi tiết tạo nên PushSubscription.

Mỗi trình duyệt sử dụng một Dịch vụ đẩy khác nhau, chẳng phải chúng có API khác nhau hay không?

Tất cả các dịch vụ đẩy đều yêu cầu cùng một API.

API phổ biến này được gọi là Giao thức đẩy web và mô tả yêu cầu mạng mà ứng dụng của bạn cần thực hiện để kích hoạt thông báo đẩy.

Nếu tôi đăng ký cho một người dùng trên máy tính, thì họ có đăng ký trên điện thoại không?

Rất tiếc là không. Người dùng phải đăng ký chế độ đẩy trên từng trình duyệt mà họ muốn nhận thông báo. Ngoài ra, hãy lưu ý rằng thao tác này sẽ yêu cầu người dùng cấp quyền trên từng thiết bị.

Điểm đến tiếp theo

Lớp học lập trình