本文略帶PHP代碼需要在PHP環境下使用
介紹
????????AJAX (Asynchronous JavaScript and XML) 是一種創建快速動態網頁應用的開發技術,它允許網頁在不重新加載整個頁面的情況下,與服務器交換數據并更新部分網頁內容。例如,在我們做爬蟲的時候發現有些頁面可以打開圖片、視頻等資源,但是無論我們怎么查找都無法查到資源的url到底在哪里,這就說明網頁很有可能把資源的url藏在了javascript的代碼中,通過XMLHttpRequest 對象向后端發送請求,在前端篩選處理信息并呈現出來。
XMLHttpRequest 對象
????????所有現代瀏覽器均支持 XMLHttpRequest 對象。XMLHttpRequest 用于在后臺與服務器交換數據。這意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。
? ? ? ? 在這個html的代碼中,我們設置了一個按鈕,點擊這個按鈕就會觸發函數ajax(),在ajax函數中,我們首先創建了一個XMLHttpRequest對象,接下來使用我們創建的對象向指定的url發送get請求,在加載完畢后(onreadystatechange)以后就會觸發匿名函數,把請求的內容放到id為aj的標簽里面。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ajax</title><script>function ajax() {var xhr = new XMLHttpRequest();xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {document.getElementById("aj").innerHTML = xhr.responseText;}}xhr.open("GET", "http://127.0.0.1:8000/a", true);xhr.send();}</script>
</head>
<body><button onclick="ajax()">click me</button><div id="aj"></div>
</body>
</html>
? ? ? ? 我們創建了一個服務器監聽8000端口,并且設置這個網頁的url為……/a,但是我們使用瀏覽器打開html文件以后發現,怎么點擊按鈕都打不開。
? ? ? ? 在束手無策的時候,我們不得已打開抓包工具,然后查看console(終端)發現它給我們的提示是:
? ? ? ? 這個報錯給我們的提示大概內容是不允許我們的內容跨站加載(瀏覽器的同源策略),于是要想訪問127.0.0.1:8000我們現在要做的就是把這個html文件也放到對應的url上。為了更快加載這些資源,我們這次選擇php語言做服務端。
<?php$request_url = $_SERVER['REQUEST_URI'];$request_url = rtrim($request_url, '/');$request_url = ltrim($request_url, '/') ;switch($request_url){case 'a':echo "Hello from A";break;case 'b':if(file_exists("1.html")){include("1.html"); }else{echo "not found file 1.html";}break;default:echo "404 Not Found";break;}
?>
????????這個代碼的大致思路是通過$_SERVER['REQUEST_URL']獲得我們輸入的url,在接下來的rtrim和ltrim函數中,我們把獲得的url前后的'/'去掉,接下來通過switch根據不同的url向客戶端返回不同的網頁。之后我們在終端輸入php -S 127.0.0.1:8000 filename.php這樣我們的服務器就會運行在指定的端口。
? ? ? ? 再在終端打開測試即可。
? ? ? ? 接下來我們點擊按鈕后發現,瀏覽器沒有刷新頁面就給我們加載出來了想要的信息。
onkeyup
? ? ? ? 在上面的代碼中,我們每次點擊按鈕都會給我們進行一次請求,但是這樣使用起來顯然有點麻煩,我們如果輸入某些驗證類的東西,每次都要重新點擊會加重我們的負擔,那么在html標簽中給我們準備了onkeyup,讓我們可以改變輸入的值以后就會被瀏覽器檢測到,進而讓我們不再需要點擊,而是直接輸入改變值就可以和后端對接。
????????onkeyup 是一個HTML事件屬性,用于在用戶釋放鍵盤上的某個鍵時觸發指定的 JavaScript 函數或代碼。這個事件通常用于捕獲用戶在輸入框中輸入的內容,并在用戶停止輸入時執行某些操作,例如實時搜索、驗證輸入或動態更新頁面內容。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>sub</title><script>function showHint(str) {if (str.length == 0) {document.getElementById("hint").innerHTML = "";return;} else {var xmlhttp = new XMLHttpRequest();xmlhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {document.getElementById("hint").innerHTML = this.responseText;}};xmlhttp.open("GET", "http://127.0.0.1:8000/sub?id=" + str, true);xmlhttp.send();}}</script>
</head>
<body><input type="text" onkeyup="showHint(this.value)"><div id = "hint"></div>
</body>
</html>
? ? ? ? 在測試的過程中,我做了這樣的一個前端代碼,有一個文本輸入的input我們每次輸入數據都可以觸發函數showHint()。接下來我們看一下服務端怎么構造。
<?php$request_url = $_SERVER['REQUEST_URI'];$request_url = rtrim($request_url, '/');$parsed_url = parse_url($request_url);$path = $parsed_url['path'] ?? '';$query = $parsed_url['query'] ?? '';$path = ltrim($path, '/');switch($path){case 'a':echo "Hello from A";break;case 'b':if(file_exists("1.html")){include("1.html"); }else{echo "not found file 1.html";}break;case 'sub':parse_str($query, $query_params);$id = $query_params['id'] ?? '';if(!isset($id) || empty($id)){include("2.html");}else if($id === '1'){echo "這是1";}else if($id === '2'){echo "這是2";}else{echo "not found";}break;default:echo "404 Not Found";break;}
?>
????????在這個代碼中,我們輸入的url為……/sub時就會呈現html文件,里面是一個輸入框。我們可以傳入參數,html文件會給我們的服務端發送帶著id參數的請求,而不同的id則會觸發不同的提示。
fetch函數
????????Fetch API 是一種現代的、功能強大的網絡請求工具,它允許你通過 JavaScript 異步地請求資源,而不需要使用傳統的 XMLHttpRequest 對象。Fetch API 可以簡潔地發起 HTTP 請求,并處理服務器的響應。Fetch API 基于 Promise 設計,使得異步操作更加簡潔和易于理解。
? ? ? ? fetch函數的使用會讓你的代碼更加易讀,使用它處理url會讓代碼更加優雅。它的基本使用方法是:
fetch(url).then(response => response.json()) // 解析 JSON 數據.then(data => console.log(data)) // 處理數據.catch(error => console.error('Error:', error)); // 錯誤處理
我們按照這種方法修改一下2.html的代碼。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>sub</title><script>function showHint(str) {if (str.length == 0) {document.getElementById("hint").innerHTML = "";return;} else {fetch("http://127.0.0.1:8000/sub?id=" + str).then(response => response.json()).then(data => {document.getElementById("hint").innerHTML = data.result;}).catch(error => console.log(error));}}</script>
</head>
<body><input type="text" onkeyup="showHint(this.value)"><div id = "hint"></div>
</body>
</html>
? ? ? ? 注意:一定要按照1.加載數據2.處理數據3.捕獲異常的順序,1和2不能合并在一起,因為js沒有多線程的編程方法,這就導致了它的異步工作處理非常發達,如果1和2寫在一起,就會導致,數據還沒有從服務器發過來就被開始處理,這通常會導致報錯。
? ? ? ? 測試后發現和之前相同,能正常使用