AJAX 是 Asynchronous JavaScript and XML 的縮寫,它並不是一種新的技術,而是綜合了多項瀏覽器端網頁開發技術的方法。字面上是非同步的 JavaScript 與 XML 技術,不過實務上廣泛地使用 JSON 資料格式來做交換,不限於 XML。
簡單來說,就是用 JavaScript 來達成不需要重新載入整個頁面,就可以從後端拿到資料後,更新網頁上的內容。
圖:AJAX 流程圖
圖:情境流程
用身為一個 WordPress 使用者的情境,可能會是這樣:
使用者 Terry 在網站上的訂閱電子報輸入框輸入 Email,並按下訂閱按紐,接著後端分析 Email 正確,把此 Email 加入電子報寄發清單,並回覆訂閱成功訊息給前端。Terry 看到電子報的輸入框消失,變成您已訂閱成功字樣,心滿意足地離開網頁...。
在 WordPress 的 AJAX 溝通的的主要入口為 admin-ajax.php
這個檔案,雖然它的檔名上有 admin 這個單字,位置在 wp-admin 目錄之下,乍看之下會讓人覺得,它是不是只用在後台管理?
或許初期是為了後台而設計,所以才被放在 wp-amdin 目錄中,不過它的使用範圍不僅限於後台管理員區域的請求。前端的 AJAX 請求也適用。
在介紹 admin-ajax.php 檔案是如何處理 AJAX 請求之前先來認識 WordPress 中很常見的鉤點命名的方式—「動態鉤點」 (dynamic hook)。
動態鉤點並不是和一般的鉤點一樣,直接命名在程式碼中,而是它的名稱中某一部分是字串變數,由傳入的變數來決定它最後的名稱。
圖:官方文件鉤點查詢頁面 文件
例如,查詢官方文件,會發現有一個鉤點名稱長這樣:
wp_ajax_{$action}
鉤點名稱中的 {$action}
在這份文件中的意思為可替換的變數。這樣說感覺有點抽像不好懂,讓我們實際來看看 admin-ajax.php 中的程式碼片段。
圖:wp-admin/admin-ajax.php 檔案尾端內容
在 admin-ajax.php 的內容尾端如下:
第 1 行:$_REQUEST['action']
可以讀取到 $_GET 以及 $_POST 裡鍵值為 action 的變數,稍後看到 do_action 函式埋的鉤點全名為 wp_ajax_
及 wp_ajax_nopriv_
與此字串的組合。。
第 17 行:定義了此鉤點,是使用者登入時才會觸發的鉤點。不過在這之前的第 5 行至第 7 行,如果動態的鉤點中沒有任何被註冊的函式,則會回應 HTTP 狀態碼 400
。
第 32 行:定義了此鉤點,是使用者未登入時,才會觸方的鉤點。不過在這之前的第 20 行至第 22 行,如果動態的鉤點中沒有任何被註冊的函式,則會回應 HTTP 狀態碼 400
。
為了測試,我們先在佈景主題裡的 functions.php 底部寫一下測試用的程式碼,來看看結果如何。
圖:佈景主題 functions.php 測試 (Gist)
第 6 行至第 23 行:將測試用的 JavaScript 檔案載入。
第 7 行:啟用 jQuery 依賴,讓 JavaScript 檔案使用。
第 9 行和第 17 行定義的 script ID 要一致。
第 18 行:定義一個全域的 demo_object
物件在 window 物件下。
第 19 至 21 行:定義變數,放在第 18 行定義的物件中,供前端使用。
第 30 至 33 行:這是負責處理 AJAX 請求的程式碼。
第 35 行:註冊載入 JavaScript 檔案的鉤點。
第 36 行:註冊使用者已登入狀態下,處理 AJAX 請求的鉤點。
第 37 行:註冊使用者未登入狀態下,處理 AJAX 請求的鉤點。
注意:鉤點的名稱結合了 $action 變數。
圖:JavaScript 檔案內容
這一份是 JavaScript 檔案,重點在
第 2 行:在 PHP 定義給前端用的物件。
第 9 行: action
是決定動態鉤點名稱的變數。
在測試頁面的輸出以下 HTML。
<button id="simple-button">按這裡測試</button>
點擊即可看到跳出視窗訊息「這是 2023 鐵人賽的範例唷!」。
上述的例子並沒有考慮到檢查請求是否合法,考量到安全性的問題,必須使用 WordPress 的 nonce
功能來驗證請求,降低被 XSS (Cross-site Scripting, 跨站腳本攻擊) 的風險。
函式名稱 | 說明 |
---|---|
wp_create_nonce | 產生一個臨時性的字串,用來驗證請求或確認提交表單是來自網站本身,而不是外部的請求。 |
check_ajax_referer | 驗證 AJAX 請求中的 nonce 值,確保請求是合法的。常用於 AJAX 安全性驗證。 |
wp_verify_nonce | 驗證 nonce 值是否有效,主要用於非 AJAX 的請求,如表單提交。不過也可以用來驗證 AJAX 請求。 |
讓我們使用上述函式來修改之前的範例。
圖:佈景主題 functions.php 測試
第 21 行:使用 wp_create_nonce 函式,產生 nonce 並放進 demo_object 這個給前端使用的變數。
第 32 行:使用 check_ajax_referer 來驗證 nonce。第二個參數名稱是 nonce 的欄位名稱,test_nonce 是故意取名的,搭配著 JS 檔案的程式碼比較好理解。如果不指定欄位名稱的話,預設的欄位名稱為 _wpnonce
。
圖:JavaScript 檔案內容
第 10 行:指定 nonce 的欄位名稱。如果在驗證用的 PHP 程式碼沒有指定欄位名稱,這裡使用欄位名稱為 _wpnonce
。
圖:改用 wp_verify_nonce 方法驗證
這邊是使用 wp_verify_nonce 進行驗證的版本,是麻煩了些,因為還需先檢查全域的 $_POST 或 $_GET 變數有沒有存在該資料所使用的鍵值。
今天主要介紹了 WordPress 使用註冊 AJAX 動態鉤點來實作 AJAX 設計及使用方法,很重要的一點,一定要經過驗證 nonce 的過程,以提高前端與後端進行資料交換的安全性喔。那麼除了這個作法以為,還有其它的方式嗎?有的,那就是 REST API。在明天的文章中,筆者會介紹 WordPress 的 REST API 機制,及和傳統作法之間的比較喔。
課後思考:
除了訂閱電子報的例子之外,還有哪些網站功能常會使用 AJAX?
前篇解答參考:
過濾輸出的字串以達到最基本的跨站腳本攻擊的防護。另外輸入的部分更是必須嚴格過濾。如果好奇查看一下網站伺服器的 access log,會發現每天網站上造訪的不是只有人類,有時候還會發現惡意的網路爬蟲,這些來者不善的機器人一直試著塞資料來測試是否能達成 SQL注入 (SQL injection) 來造成漏洞,以取得資料庫的權限,更甚者是整個網站的權限。因此無論是資料的輸出和輸入,都必須嚴格檢查,好好把關。