Select Page
開發人員必看的 Web Push 功能教學

開發人員必看的 Web Push 功能教學

Web Push 是一種標準的 Web 協議,允許網站向使用者發送推播通知。這項功能可用於各種目的,例如:

  • 提醒使用者有新的內容或更新
  • 提供即時通知,例如交易狀態或聊天訊息
  • 提高使用者參與度

準備工作

  • 前端訂閱推播服務的 js 檔案
  • 前端訂閱推播服務的網頁,需要包含訂閱服務的 js
  • 後端紀錄使用者訂閱資訊的服務
  • 後端推播訊息的服務
  • 後端註冊訊息伺服器的程式碼

建立前端網頁的訂閱表單

這個檔案將包含安裝、激活、攔截請求和推播事件的處理器。創建一個名為sw.js的檔案,並將其放在你網站的根目錄下

// 安裝Service Worker
self.addEventListener('install', function(event) {
    console.log('Service Worker 安裝成功');
});

// Service Worker 激活
self.addEventListener('activate', function(event) {
    console.log('Service Worker 激活成功');
});

// 監聽推播事件
self.addEventListener('push', function(event) {
    var title = '推播通知';
    var options = {
        body: '這是一條推播消息。',
        icon: 'icon.png',
        badge: 'badge.png'
    };

    event.waitUntil(self.registration.showNotification(title, options));
});

在你的網站上註冊一個Service Worker,這是實現Web推播的必要步驟。Service Worker將在背景執行,即使用戶沒有直接訪問你的網站也能接收通知。通常會把下面的 javascript 寫在首頁中,觸發訂閱的條件。

// 在主要的JavaScript檔案中
function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/\-/g, '+')
        .replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('Service Worker 注册成功:', registration);
  }).catch(function(error) {
    console.log('Service Worker 注册失败:', error);
  });
}
navigator.serviceWorker.ready.then(function(registration) {
  if (!registration.pushManager) {
    alert('此瀏覽器不支持推播通知');
    return false;
  }
const applicationServerKey = 'your publice key';
  
// 訂閱推播
  registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(applicationServerKey)
  }).then(function(subscription) {
    console.log('推播訂閱成功:', subscription);

    // 發送訂閱資訊到後端
    fetch('https://your_webpush_server/subscribe', {
      method: 'post',
      headers: {
        'Content-type': 'application/json'
      },
      body: JSON.stringify({
        subscription: subscription
      }),
    });
  }).catch(function(error) {
    console.log('推播訂閱失败:', error);
  });

提供紀錄訂閱訊息的服務

這一段的作法很多,通常用你原本伺服器中的解決方案,例如 php,asp.net,nodejs,python,GO等,我這邊為了方便,用nodejs示範下

const express = require('express');
const cors = require('cors');

const bodyParser = require('body-parser');
const app = express();
app.use(cors());
app.use(bodyParser.json());

const subscriptions = {}; // 在實際應用中,應使用資料庫儲存訂閱資訊

const webPush = require('web-push');
    // 設置你的VAPID鑰匙
    webPush.setVapidDetails(
        'mailto:[email protected]',
      	'your publiec key',
      	'your private key'
      };

app.post('/subscribe', (req, res) => {
    const subscription = req.body;
    const key = subscription.endpoint; // 使用endpoint作為唯一鑰匙
    subscriptions[key] = subscription;

    console.log('subscripted');
    console.log(subscription);
    
    // subscription是從前端發送到後端的訂閱對象
    webPush.sendNotification(subscription.subscription, '消息內容')
        .then(result => console.log('推播成功'))
        .catch(err => console.log('推播失敗', err));

    res.status(200).json({message: '訂閱成功'});
});

app.listen(8060, () => console.log('伺服器運行在8060端口'));

其中 sendNotification 平常應該是要放在 webpush service中的,這邊加入是用來測試使用

生成VAPID鑰匙 (自願應用伺服器身份驗證)

大部分現代瀏覽器(如Chrome、Firefox、Edge)都支持Web推播API,但是如果你不用市面上的解決方案如 OneSignal 而是要直接與這些瀏覽器的推播服務交互的話,需要使用VAPID(自願應用伺服器身份驗證)鑰匙進行身份驗證。

生成 VAPID Key 的方法如下

npx web-push generate-vapid-keys

記住保存生成的鑰匙。公鑰將在前端用於訂閱推播,私鑰將在後端用於發送推播。


如果你無法使用npx(它通常隨npm自動安裝,作為npm 5.2.0及更高版本的一部分),那麼你可以通過下載最新版本的 nodejs

https://nodejs.org/

或是升級Node.js,或使用版本管理器如nvm(Node Version Manager)來管理不同版本的Node.js。

參考資料

https://developer.mozilla.org/en-US/docs/Web/API/Push_API

改進你的WordPress網站:使用JavaScript隱藏不需要的欄位

改進你的WordPress網站:使用JavaScript隱藏不需要的欄位

在WordPress中利用JavaScript隱藏特定欄位是一種有效的方式來改善網站的用戶體驗和介面設計。這需要創建並嵌入自定義的JavaScript腳本到你的WordPress主題中。這個過程涉及幾個關鍵步驟,包括在主題資料夾中創建JavaScript檔案、編寫用於隱藏特定元素的JavaScript代碼、並透過functions.php檔案將這個腳本加入到WordPress網站中。

1.創建JavaScript檔案

在你的主題資料夾(通常位於wp-content/themes/你的主題名稱)中創建一個新的JavaScript檔案。例如,你可以創建一個名為custom-script.js的檔案。

2.編寫JavaScript代碼

custom-script.js檔案中,寫下用於隱藏欄位的JavaScript代碼。例如,如果你想隱藏一個ID為my-field的元素,代碼可能如下:

document.addEventListener('DOMContentLoaded', function () {
    var field = document.getElementById('my-field');
    if (field) {
        field.style.display = 'none';
    }
});

3.將JavaScript檔案加入到WordPress

在你的主題的functions.php檔案中,使用wp_enqueue_script函數將剛剛創建的JavaScript檔案加入到你的網站中。例如:

function add_custom_scripts() {
    wp_enqueue_script('custom-script', get_template_directory_uri() . '/custom-script.js', array('jquery'), null, true);
}
add_action('wp_enqueue_scripts', 'add_custom_scripts');

這段代碼會將你的custom-script.js檔案加入到WordPress,並確保它在網頁加載時被執行。

4.更新並檢查你的網站

更新你的WordPress網站並訪問前台,檢查欄位是否已被隱藏。

5.注意 js 的路徑

如果你使用的是子佈景主題,那需要把 get_template_directory_uri() 更改成 get_stylesheet_directory_uri()

function add_custom_scripts() {
    wp_enqueue_script('custom-script', get_stylesheet_directory_uri() . '/custom-script.js', array('jquery'), null, true);
}
add_action('wp_enqueue_scripts', 'add_custom_scripts');

這個技術對於希望定制其網站外觀和功能的WordPress用戶來說非常有用,特別是對於那些希望隱藏不必要元素以簡化頁面佈局的用戶。雖然這個過程可能需要一些基本的PHP和JavaScript知識,但它為用戶提供了增強和個性化其網站的機會。

值得注意的是,在進行這些更改時,應該小心操作,並在更改主題檔案之前進行備份。此外,如果你使用子主題,應在子主題中進行所有更改,以避免在主題更新時丟失定制的代碼。這種方法不僅提高了網站的專業程度,還有助於保持良好的用戶體驗。

延伸閱讀:

使用 jQuery 移動元素(Div)

常常有需求要事後調整前台的畫面,尤其現在前端 javascript 的框架一大堆,只能事後處理,把元素的位置變來變去,我這邊舉利用 div 來代表,如何把元素變換位置,讓排版更簡單且容易些。

先準備有原來的 div

<div id="source">
  ....
</div>

想要把原來的Div移動到目的地的div,id 訂為 dest

<div id="dest">
  ....
</div>

JQuery 程式碼 appendTo(),把 div 移動到目的地 div 的裡面

$("#source").appendTo("#dest");

除了 appendTo() 最常用,還整理幾個常用的寫法,放在下面

$("#source").insertBefore("#dest");
$("#source").insertAfter("#dest");
$("#source").prependTo("#dest");
$("#source").appendTo("#dest");

參考資料

https://stackoverflow.com/questions/1279957/how-to-move-an-element-into-another-element

如何解決 ASP.NET MVC WEB API 遇到 CORS 錯誤

如何解決 ASP.NET MVC WEB API 遇到 CORS 錯誤

要用 ASP.NET MVC 開發 WEB API給大家使用,前端 javascript 工程師,總是會遇到錯誤訊息 Response to preflight request doesn’t pass access control check: It does not have HTTP ok status,這是一個超常見的 CORS (Cross-Origin Resource Sharing) – 跨來源資源共用錯誤訊息,網路上很多解法,但可以用的情境都不太一樣,我這邊提供一個我覺得最簡單請快速的方法給大家。

解決方法是利用 NuGet 先安裝 Cors 套件

先上 NuGet 搜尋 Microsoft.AspNet.Cors , Microsoft.AspNet.WebApi.Cors,並且安裝起來

將 Cors 註冊起來

在 App_Start/WebApiConfig.cs 的 Register function 加入以下的程式碼

config.EnableCors();

會是長成以下的程式碼

        public static void Register(HttpConfiguration config)
        {
            // Web API 設定和服務
            config.EnableCors();

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

設定 WebAPI 的CORS 權限

我們可以在 WebApi 的 Class 上面設定,也可以在 Function 上做標記,但要注意的是不能有多個 CORS 繫結,如果你在 web.config 中設定,這邊就不能再做設定,如果你在 class 等級上設定了, function 等級就不能再設定,也是因為這個原因,所以我喜歡在 function 等級設定或是 class 等級上設定,web.config 比較少去做設定,雖然他有不用修改程式碼的好處。

其中設定值的資料參考請看https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference

  • origins,可以設定 (*) ,也可以指定特定網域,看你要對誰開放
  • headers,通常用 (*) 就可以了
  • methods,通常用 (*) 就可以了
    [System.Web.Http.Cors.EnableCors(origins: "https://yourdomain.com", headers: "*", methods: "*")]
    public class ValueController : ApiController
    {
    }

CORS web.config 的設定方法

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.yourdomain.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>

利用 javascript 以及 jquery 由前端網頁發送 email

// 發送email  
function sendEmail(title,text){
    var email = document.createElement("a");
    email.id = "sendemail";   
    email.href = "mailto:[email protected]?subject="+title+"&body="+ text;
    email.click();
    }

當使用者在網頁中,再連絡表單中填入資訊後,我們通常會寫入後端資料庫,並且發送通知,以方便管理者使用,但沒有資料庫的人,就需要仰賴使用者自己的電子郵件了,為了統一格式方便,我們還是提供聯絡表單,先幫忙使用者把資料正規化一下,然後在協助它們送出資訊給後端的管理者