国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

在Web應(yīng)用程序中發(fā)送通知的方法及教程

了解如何使用JavaScript在您的網(wǎng)站或Web應(yīng)用程序中發(fā)送通知。本文介紹了使用服務(wù)工作者、通知API和推送API發(fā)送本地通知和推送通知的步驟。

有沒有想過一些網(wǎng)頁、網(wǎng)址或您在瀏覽器上使用的其他喜愛應(yīng)用程序如何發(fā)送通知給您?這并不是魔法,有一些方法可以做到,本文將介紹其中一種方法。

在Web開發(fā)世界中,通過引入一些網(wǎng)頁API,現(xiàn)在更容易完成一些可能需要使用移動應(yīng)用程序才能實現(xiàn)的任務(wù)之一,即發(fā)送通知。使用通知API和推送API結(jié)合服務(wù)工作者,在Web瀏覽器上發(fā)送通知變得比以往任何時候都更簡單。

本文將解釋如何在您的網(wǎng)站或Web應(yīng)用程序中發(fā)送通知,并使用JavaScript進行演示。

通知可以分為兩種類型:

  • 本地通知:由應(yīng)用程序自己生成。

  • 推送通知:由服務(wù)器(后端)通過推送事件生成的通知。例如,您的最喜歡的YouTuber剛剛發(fā)布了一部視頻,您即使不在YouTube Web應(yīng)用程序上,也會在獲取網(wǎng)絡(luò)連接后獲得通知。

本文將在文章中詳細(xì)介紹每一種類型的通知。在開始之前,我們需要了解哪些內(nèi)容?

發(fā)送通知所需的組件:

  • 服務(wù)工作者:服務(wù)工作者實際上充當(dāng)Web應(yīng)用程序、瀏覽器和網(wǎng)絡(luò)(當(dāng)網(wǎng)絡(luò)可用時)之間的代理服務(wù)器。它們的目的是為了實現(xiàn)有效的離線體驗,攔截網(wǎng)絡(luò)請求,并根據(jù)網(wǎng)絡(luò)的可用性采取適當(dāng)?shù)男袆?。它們還將允許訪問推送通知和后臺同步API。服務(wù)工作者的一個好例子是當(dāng)您離線時,仍然可以從YouTube通知服務(wù)器向您的瀏覽器發(fā)送通知,但直到您重新連接到互聯(lián)網(wǎng)時,您才會收到通知。

  • 通知API:該API用于像移動設(shè)備一樣在您的Web應(yīng)用程序中向用戶顯示通知提示,例如當(dāng)用戶在您的應(yīng)用程序中點擊按鈕或執(zhí)行操作時。

  • 推送API:該API用于從服務(wù)器獲取推送消息。

發(fā)送本地通知

在發(fā)送本地通知到您的Web應(yīng)用程序中,我們將采取以下3個步驟:

  • 我們需要使用requestPermission方法通過通知API來請求用戶發(fā)送通知的權(quán)限。

  • 如果權(quán)限被授予,我們的服務(wù)工作者現(xiàn)在會監(jiān)聽推送事件。當(dāng)推送事件到達(dá)時,服務(wù)工作者將從消息中提取信息并使用通知API顯示通知。

  • 如果權(quán)限未被授予,您還應(yīng)正確處理該情況的代碼。

讓我們首先編寫一個簡單頁面的示例代碼,在單擊“提醒我”按鈕時實現(xiàn)本地通知的功能。

HTML代碼

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>示例</title>
</head>
<body>
    <button class="notify">提醒我</button>
</body>
<script src="./script.js"></script>
</html>

Javascript 代碼 script.js

const Notifybtn = document.querySelector(".notify");
const sendNotification = ()=>{
    if(!("Notification" in window)){
        throw new Error("您的瀏覽器不支持推送通知");
    }
    Notification.requestPermission().then((Permission)=>{
        const notificationOptions = {
            body:"歡迎使用 JavaScript 推送通知",
            icon:"./image.png"
        }
        new Notification("推送通知",notificationOptions);
    })
};
Notifybtn.addEventListener("click", sendNotification);

在上面的代碼中,我們有 sendNotification 函數(shù),我們首先檢查用戶的瀏覽器是否支持通知,然后我們請求用戶允許發(fā)送通知,如果沒有授予權(quán)限,我們將無法發(fā)送通知。
為了發(fā)送通知,我們使用通知構(gòu)造函數(shù),將通知標(biāo)題作為第一個參數(shù),將通知選項作為第二個參數(shù)。運行這個你會得到這樣的東西

基本本地通知

讓我們稍微加強一下,我們想要發(fā)送更具交互性的通知,用戶可以點擊按鈕或我們想要進行的任何類型的交互。讓我們嘗試修改我們的代碼來滿足這種需求。

const sendNotification = ()=>{
    if(!("Notification" in window)){
        throw new Error("您的瀏覽器不支持推送通知");
    }
    Notification.requestPermission().then((Permission)=>{
        const notificationOptions = {
            body:"歡迎使用 JavaScript 推送通知",
            icon:"./image.png",
            actions: [
      {
        action: "thanks",
        title: "Thanks",
      },
      {
        action: "view_profile",
        title: "View Profile",
      },
    ],
        }
        new Notification("推送通知",notificationOptions);
    })
};

在這里,我們向通知選項添加了 actions 屬性,用戶可以在通知上有按鈕進行交互。當(dāng)您運行此命令時,您會收到如下錯誤:

當(dāng)我們嘗試使用通知構(gòu)造函數(shù)創(chuàng)建可交互操作時出現(xiàn)錯誤

相當(dāng)明確的錯誤消息,僅在使用服務(wù)工作者時才支持操作,我們該怎么做?

使用 Service Worker 發(fā)送通知

首先,我們需要有 Service Worker 文件并注冊 Service Worker。讓我們的 serviceWorker.js 文件中只有一個簡單的 console.log 。

//serviceWorker.js
console.log("您好,歡迎來到服務(wù)人員")

我們現(xiàn)在可以繼續(xù)注冊我們的 Service Worker。

const registerServiceWorker = async () => {
  if ("serviceWorker" in navigator) {
    try {
      const registration = await navigator.serviceWorker.register(
        "serviceWorker.js",
        {
          scope: "./",
        }
      );
      return registration;
    } catch (error) {
      console.error(`注冊失敗 ${error}`);
    }
  }
};

因此,是時候通過修改我們的 sendNotification 函數(shù)來創(chuàng)建具有交互操作的通知

// script.js
const sendNotification = async () => {
  let notificationOptions = {
    body: "Toy模板網(wǎng)向您發(fā)送了好友請求",
    icon: "./image.png",
   data: {
      requestId: "1234",
      username: "elonmusk"
    },
    actions: [
      {
        action: "accept",
        title: "Accept",
      },
      {
        action: "view_profile",
        title: "View Profile",
      },
    ],
    tag: "friend_request",
  };
  const sw = await registerServiceWorker();
  sw.showNotification("Friend Request", notificationOptions);
};

在這里你有它

當(dāng)您單擊時,似乎沒有發(fā)生任何事情:) 讓我們進一步監(jiān)聽 serviceWorker 中的 notificationclick 事件。

// serviceWorker.js

self.addEventListener("notificationclick", (event) => {
  event.notification.close();

  switch (event.notification.tag) {
  case "friend_request":{
    switch (event.action) {
      case "accept": {
        console.log("accept request API call.. with ", event.notification.data);
      }

      case "view_profile":
        {
          //直接進入個人資料頁面
          event.waitUntil(
            clients
              .matchAll({
                type: "window",
                includeUncontrolled: true,
              })
              .then((windowClients) => {
                const matchingClient = windowClients.find(
                  (wc) => wc.url === urlToOpen
                );

                if (matchingClient) {
                  return matchingClient.focus();
                } else {
                  return clients.openWindow(event.notification.data.username);
                }
              })
          );
        }

        break;
      // 處理其他動作...
    }
  }
  }
});

在這里您可以看到我們有兩個操作“接受請求”和“查看個人資料”,當(dāng)通知的標(biāo)簽為“friend_request”時我們會執(zhí)行該操作,并且我們基本上是在通知中傳遞數(shù)據(jù),這是需要注意的重要事項。

發(fā)送推送通知

到目前為止,我們已經(jīng)能夠在我們的網(wǎng)絡(luò)應(yīng)用程序中發(fā)送本地通知,這很酷,對吧?但大多數(shù)時候,在構(gòu)建實際應(yīng)用程序時,您需要的是推送通知;從服務(wù)器生成的通知。在本節(jié)中,我們將在 ExpressJS 中建立后端服務(wù)器。讓我們設(shè)置我們的服務(wù)器。

// app.js

const express = require("express");
const cors = require("cors");
require("dotenv").config();

const { API_PREFIX } = process.env;
const app = express();
const { models } = require("./config/db");
const { sendNotification } = require("./utils/helper");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
  cors({
    origin: "*",
  })
);
app.disable("x-powered-by");
module.exports = app
// index.js
const app = require("./app");
const { PORT } = process.env;
const connection = require("./config/db");
(async () => {
    await connection
      .sync()
      .then(() => {
        console.log("Database successfully connected");
      })
      .catch((err) => {
        console.log(err.message);
        return process.exit(1);
      });
    app.listen(PORT, () => {
        console.log(
          `<<<<<<<<<<<<<<<< Yeeeep,Server running on port ${PORT}..>>>>>>>>>>>`
        );
    });
  })();

這樣,我們的后端服務(wù)器就啟動并運行了(PS:由于某些導(dǎo)入,此代碼片段將無法正常工作,在本文末尾,您可以找到所有代碼的 GitHub 存儲庫的鏈接:文章結(jié)尾”

讓我們再次回退到前端...為了能夠發(fā)送推送通知,我們需要以下內(nèi)容:

  • VAPID 鍵

  • Web 應(yīng)用程序必須通過 Service Worker 訂閱推送服務(wù)

VAPID:Web Push 的自愿應(yīng)用程序服務(wù)器標(biāo)識是一個允許后端服務(wù)器向推送服務(wù)(瀏覽器特定服務(wù))標(biāo)識自身的規(guī)范。這是一種安全措施,可防止其他人向應(yīng)用程序的用戶發(fā)送消息。

APID 密鑰如何確保安全?
簡而言之:
您在應(yīng)用程序服務(wù)器上生成一組私鑰和公鑰(VAPID 密鑰)。
當(dāng)前端應(yīng)用程序嘗試訂閱推送服務(wù)時,公鑰將被發(fā)送到推送服務(wù)。現(xiàn)在推送服務(wù)知道來自您的應(yīng)用程序服務(wù)器(后端)的公鑰。subscribe 方法將為您的前端 Web 應(yīng)用程序返回一個唯一的端點。您將將此唯一端點存儲在后端應(yīng)用程序服務(wù)器上。
從應(yīng)用程序服務(wù)器,您將向剛剛保存的唯一推送服務(wù)端點發(fā)出 API 請求。在此 API 請求中,您將使用私鑰對 Authorization 標(biāo)頭中的一些信息進行簽名。這允許推送服務(wù)驗證請求是否來自正確的應(yīng)用程序服務(wù)器。
驗證標(biāo)頭后,推送服務(wù)會將消息發(fā)送到前端 Web 應(yīng)用程序。

讓我們繼續(xù)生成 VAPID 密鑰,我們需要在您的后端或全局安裝“web-push”dendency...

npm i web-push

安裝后就可以運行

npx web-push generate-vapid-keys

你有這樣的東西

//serviceWorker.js
const urlB64ToUint8Array = (base64String) => {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding)
    .replace(/\-/g, "+")
    .replace(/_/g, "/");
  const rawData = atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
};

self.addEventListener("activate", async () => {
  try {
    const applicationServerKey = urlB64ToUint8Array(
      "<YOUR_PUBLIC_KEY>"
    );
    const options = { applicationServerKey, userVisibleOnly: true };
    const subscription = await self.registration.pushManager.subscribe(options);
    console.log(JSON.stringify(subscription))
  } catch (err) {
    console.log("Error", err);
  }
});

在這里,我們監(jiān)聽 Service Worker 注冊和激活的時間,我們使用 VAPID 公鑰,將其從 Base64 字符串轉(zhuǎn)換為訂閱選項所需的數(shù)組緩沖區(qū),并且我們還在屬性中添加了 userVisibleOnly設(shè)置為 true。您需要始終將 userVisibleOnly 發(fā)送為 true 。該參數(shù)限制開發(fā)者使用推送消息進行通知。也就是說,開發(fā)人員將無法使用推送消息在不顯示通知的情況下靜默向服務(wù)器發(fā)送數(shù)據(jù)。目前,它必須設(shè)置為 true,否則您會收到權(quán)限被拒絕的錯誤。本質(zhì)上,出于隱私和安全考慮,目前不支持靜默推送消息。

當(dāng)它成功運行時,你會看到如下內(nèi)容:

{
"endpoint":"https://fcm.googleapis.com/fcm/send/<some_strange_id>",
"expirationTime":null,
"keys":{"p256dh":"<some_key>","auth":"<some_id>"}
}

我們得到的響應(yīng)應(yīng)該保存在后端的數(shù)據(jù)庫中,因此讓我們在后端創(chuàng)建兩個端點,一個用于保存訂閱,另一個用于發(fā)送通知。

//app.jsapp.post(`/${API_PREFIX}save-subscription`, async (req, res) => {

  try {
    const subscription = JSON.stringify(req.body);
    console.log(subscription);
    const sub = await models.subscriptions.create({ subsription:subscription });
    res.status(201).json({ message: "Subscription Successful" });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }});app.post(`/${API_PREFIX}send-notification`, async (req, res) => {
  try {
    const { id } = req.body;
    const sub = await models.subscriptions.findOne({where:{id}});
    const message = {
      body: "Elon Musk sent you a friend request",
      icon: "https://media.npr.org/assets/img/2022/06/01/ap22146727679490-6b4aeaa7fd9c9b23d41bbdf9711ba54ba1e7b3ae-s800-c85.webp",
      data: {
        requestId: "1234",
        username: "elonmusk"
      },
      actions: [
        {
          action: "accept",
          title: "Accept",
        },
        {
          action: "view_profile",
          title: "View Profile",
        },
      ],
      tag: "friend_request",
    };
    await sendNotification(sub.subsription, message);
    res.json({ message: "message sent" });    
  } catch (error) {
    res.status(500).json({ message: error.message });

  }});

我們還需要創(chuàng)建有助于發(fā)送推送通知的導(dǎo)入實用函數(shù)。

// utils/helper.js
const webpush = require("web-push");
const { VAPID_PRIVATE_KEY, VAPID_PUBLIC_KEY } = process.env;
//setting our previously generated VAPID keys
webpush.setVapidDetails(
  "mailto:<your_email>",
  VAPID_PUBLIC_KEY,
  VAPID_PRIVATE_KEY
);
//function to send the notification to the subscribed device
const sendNotification = async (subscription, dataToSend) => {
  try {
   await webpush.sendNotification(subscription, JSON.stringify(dataToSend)); //string or Node Buffer
  } catch (error) {
    console.log(error);
    throw new Error(error.message);
  }
};
module.exports = { sendNotification };

我們有一個端點來保存訂閱,還有另一個端點來發(fā)送通知(PS:這只是一個示例/演示項目,在現(xiàn)實生活中,您很可能不會有一個端點來發(fā)送通知,而是一個實用程序服務(wù)(發(fā)生某些操作時可以觸發(fā)的類或函數(shù))。
現(xiàn)在讓我們回到前端來同步事物,我們首先通過調(diào)用端點將推送服務(wù)訂閱保存到數(shù)據(jù)庫。

// serviceWorker.js
const saveSubscription = async (subscription) => {
  const SERVER_URL = "http://localhost:5005/api/save-subscription";
  const response = await fetch(SERVER_URL, {
    method: "post",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(subscription),
  });
  return response.json();
};
self.addEventListener("activate", async () => {
  try {
    const applicationServerKey = urlB64ToUint8Array(
      "<YOUR_VAPID_PUBLIC_KEY>"
    );
    const options = { applicationServerKey, userVisibleOnly: true };
    const subscription = await self.registration.pushManager.subscribe(options);
    const response = await saveSubscription(subscription);
  } catch (err) {
    console.log("Error", err);
  }
});

我們就差幾步了??!現(xiàn)在讓我們使用 showNotification 函數(shù)來顯示收到的推送通知

// serviceWorker.jsconst showLocalNotification = (title, data, swRegistration) => {
  swRegistration.showNotification(title, data);};

該函數(shù)接受三個參數(shù);推送通知的標(biāo)題、notificationOption 和 Service Worker 注冊。最后,當(dāng)發(fā)出推送通知時,我們需要監(jiān)聽推送事件。

// serviceWorker.js
self.addEventListener("push", function (event) {
  if (event.data) {
    console.log("Push event!! ", JSON.parse(event.data.text()));
    showLocalNotification(
      "Notification ",
      JSON.parse(event.data.text()),
      self.registration
    );
  } else {
    console.log("Push event but no data");
  }
});

看看我們有什么:

后臺發(fā)送推送通知

我們還必須注意,當(dāng)頁面或瀏覽器刷新/重新啟動時,Service Worker 仍然保持注冊狀態(tài),并且您可能需要更改 Service Worker 文件中的某些內(nèi)容,您可以調(diào)用此函數(shù)

const unregisterServiceWorkers = ()=>{
  if (window.navigator && navigator.serviceWorker) {
    navigator.serviceWorker.getRegistrations().then(function (registrations) {
      for (let registration of registrations) {
        registration.unregister();
      }
    });
  }
}

每當(dāng)我們使用數(shù)據(jù)庫生成的 ID 訪問發(fā)送通知端點時,我們都會在您的設(shè)備上收到推送通知,這不是很酷嗎?如果您因為推送通知而希望構(gòu)建一個移動應(yīng)用程序,那么如果沒有“權(quán)衡”,您可以考慮構(gòu)建一個網(wǎng)絡(luò)應(yīng)用程序......

本文的代碼示例(https://github.com/oluwatobiisaiah/web-notification-simplified)文章來源地址http://www.zghlxwxcb.cn/article/460.html

到此這篇關(guān)于在Web應(yīng)用程序中發(fā)送通知的方法及教程的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

原文地址:http://www.zghlxwxcb.cn/article/460.html

如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請聯(lián)系站長進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包