Ajax之核心語法詳解
- 一、Ajax的核心原理與優勢
- 1.1 什么是Ajax?
- 1.2 Ajax的優勢
- 二、XMLHttpRequest:Ajax的核心對象
- 2.1 XHR的基本使用流程
- 2.2 核心屬性與事件解析
- 2.2.1 `readyState`:請求狀態
- 2.2.2 `status`:HTTP狀態碼
- 2.2.3 響應數據屬性
- 2.2.4 常用事件
- 三、HTTP請求方法與數據傳遞
- 3.1 GET請求:獲取數據
- 3.2 POST請求:提交數據
- 3.3 其他請求方法
- 四、Ajax的高級特性
- 4.1 同步與異步請求
- 4.2 請求超時設置
- 4.3 取消請求
- 五、跨域問題與解決方案
- 5.1 同源策略的限制
- 5.2 跨域解決方案
- 5.2.1 CORS(Cross-Origin Resource Sharing,推薦)
- 5.2.2 JSONP(僅支持GET請求,兼容性好)
- 六、常見問題與避坑指南
- 6.1 跨域錯誤(No 'Access-Control-Allow-Origin' header)
- 6.2 響應數據解析錯誤(JSON.parse失敗)
- 6.3 POST請求被瀏覽器轉為OPTIONS請求
Ajax(Asynchronous JavaScript and XML)是前端與后端進行數據交互的核心技術,它允許網頁在不刷新的情況下與服務器交換數據,從而實現動態更新頁面內容。
一、Ajax的核心原理與優勢
1.1 什么是Ajax?
Ajax并非單一技術,而是一組技術的集合,包括JavaScript、XML(或JSON)、HTML/CSS、DOM等,核心是通過XMLHttpRequest
對象與服務器進行異步通信。
核心特點:
- 異步通信:請求發送后無需等待服務器響應,可繼續執行其他操作;
- 局部刷新:服務器返回數據后,僅更新頁面需要變化的部分,無需全頁刷新;
- 數據交互:與服務器交換的數據格式通常為JSON(替代早期的XML,更輕量)。
1.2 Ajax的優勢
- 提升用戶體驗:避免全頁刷新,減少等待時間(如表單提交無刷新提示);
- 減少數據傳輸:僅交換必要數據,而非整個頁面HTML;
- 增強交互性:實時獲取數據(如搜索框聯想提示、實時聊天)。
二、XMLHttpRequest:Ajax的核心對象
XMLHttpRequest
(簡稱XHR)是瀏覽器提供的內置對象,用于與服務器建立連接、發送請求、接收響應,是實現Ajax的基礎。
2.1 XHR的基本使用流程
使用XHR發送請求的完整流程分為5步:
- 創建XHR對象;
- 配置請求(方法、URL、異步標識);
- 注冊響應處理函數;
- 發送請求(可選帶數據);
- 處理服務器響應。
基礎示例:發送GET請求獲取數據
// 1. 創建XHR對象
const xhr = new XMLHttpRequest();// 2. 配置請求:open(請求方法, URL, 是否異步)
xhr.open('GET', 'https://api.example.com/data', true);// 3. 注冊響應處理函數(監聽readystatechange事件)
xhr.onreadystatechange = function() {// readyState為4表示響應完成,status為200表示請求成功if (xhr.readyState === 4 && xhr.status === 200) {// 5. 處理響應數據(通常為JSON字符串)const response = JSON.parse(xhr.responseText);console.log('請求成功:', response);} else if (xhr.readyState === 4) {// 處理錯誤狀態(如404、500)console.error('請求失敗,狀態碼:', xhr.status);}
};// 4. 發送請求(GET請求無數據,參數為null)
xhr.send(null);
2.2 核心屬性與事件解析
2.2.1 readyState
:請求狀態
表示XHR對象的當前狀態,取值范圍0-4:
- 0:未初始化(
open()
未調用); - 1:加載中(
open()
已調用,send()
未調用); - 2:已加載(
send()
已調用,響應頭已接收); - 3:交互中(正在接收響應體數據);
- 4:完成(響應已全部接收)。
2.2.2 status
:HTTP狀態碼
表示服務器響應的狀態,常見值:
- 200:請求成功;
- 400:請求參數錯誤;
- 404:資源未找到;
- 500:服務器內部錯誤;
- 304:資源未修改(使用緩存)。
2.2.3 響應數據屬性
responseText
:服務器返回的文本數據(最常用,如JSON字符串);responseXML
:服務器返回的XML文檔(較少用,需服務器返回XML格式);response
:通用響應屬性(支持多種類型,如ArrayBuffer、Blob等)。
2.2.4 常用事件
readystatechange
:readyState
變化時觸發(傳統方式);load
:請求完成時觸發(無論成功或失敗,替代readystatechange
的現代方式);error
:請求失敗時觸發(如網絡錯誤);abort
:調用abort()
取消請求時觸發;progress
:接收響應數據時觸發(可用于顯示進度條)。
事件示例:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);// 加載完成(替代readystatechange)
xhr.onload = function() {if (xhr.status === 200) {console.log('請求成功:', JSON.parse(xhr.responseText));} else {console.error('請求失敗:', xhr.status);}
};// 網絡錯誤
xhr.onerror = function() {console.error('網絡錯誤,請求失敗');
};// 進度事件(接收數據時)
xhr.onprogress = function(event) {if (event.lengthComputable) {const progress = (event.loaded / event.total) * 100;console.log(`加載進度:${progress}%`);}
};xhr.send(null);
三、HTTP請求方法與數據傳遞
Ajax支持多種HTTP請求方法,最常用的是GET
和POST
,分別適用于獲取數據和提交數據。
3.1 GET請求:獲取數據
GET
請求用于從服務器獲取數據,參數通過URL的查詢字符串(?key=value&key2=value2
)傳遞。
特點:
- 參數可見(URL中),不適合敏感數據;
- 有長度限制(不同瀏覽器限制不同,通常2KB-8KB);
- 可被緩存(適合靜態數據);
- 冪等(多次請求結果相同,無副作用)。
示例:帶參數的GET請求
const xhr = new XMLHttpRequest();
// 參數通過查詢字符串傳遞(需編碼特殊字符)
const params = new URLSearchParams({name: '張三',age: 25
});
// URL:https://api.example.com/user?name=張三&age=25
xhr.open('GET', `https://api.example.com/user?${params.toString()}`, true);xhr.onload = function() {if (xhr.status === 200) {console.log('用戶數據:', JSON.parse(xhr.responseText));}
};xhr.send(null);
3.2 POST請求:提交數據
POST
請求用于向服務器提交數據(如表單、新增資源),參數放在請求體中傳遞。
特點:
- 參數在請求體中,不可見(相對安全,仍需加密敏感數據);
- 無長度限制(由服務器配置決定);
- 默認不緩存;
- 非冪等(多次請求可能有副作用,如重復提交訂單)。
示例:提交JSON數據
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/user', true);// 設置請求頭:告訴服務器請求體格式為JSON
xhr.setRequestHeader('Content-Type', 'application/json');xhr.onload = function() {if (xhr.status === 200) {console.log('提交成功:', JSON.parse(xhr.responseText));}
};// 發送JSON格式的請求體(需轉為字符串)
const data = {name: '李四',email: 'lisi@example.com'
};
xhr.send(JSON.stringify(data));
示例:提交表單數據(application/x-www-form-urlencoded
)
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/login', true);// 設置請求頭:表單默認格式
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.onload = function() {if (xhr.status === 200) {console.log('登錄成功:', JSON.parse(xhr.responseText));}
};// 發送表單格式的請求體(key=value&key2=value2)
const formData = new URLSearchParams();
formData.append('username', 'admin');
formData.append('password', '123456');
xhr.send(formData.toString());
3.3 其他請求方法
除GET
和POST
外,RESTful API常用的方法還有:
PUT
:更新資源(全量更新);PATCH
:更新資源(部分更新);DELETE
:刪除資源。
使用方式與POST
類似,只需在open()
中指定對應方法:
// PUT請求:更新用戶信息
xhr.open('PUT', 'https://api.example.com/user/123', true);// DELETE請求:刪除用戶
xhr.open('DELETE', 'https://api.example.com/user/123', true);
四、Ajax的高級特性
4.1 同步與異步請求
open()
方法的第三個參數async
控制請求是否異步:
async: true
(默認):異步請求,請求發送后繼續執行后續代碼,不阻塞頁面;async: false
:同步請求,請求發送后會阻塞頁面,直到響應完成(不推薦,影響用戶體驗)。
同步請求示例(不推薦):
const xhr = new XMLHttpRequest();
// 同步請求(async: false)
xhr.open('GET', 'https://api.example.com/data', false);xhr.send(null);// 同步請求中,send()后立即獲取響應(無需事件監聽)
if (xhr.status === 200) {console.log('同步請求結果:', JSON.parse(xhr.responseText));
}
4.2 請求超時設置
通過timeout
屬性設置請求超時時間(毫秒),超時后觸發ontimeout
事件。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/slow-data', true);// 設置超時時間為5秒
xhr.timeout = 5000;// 超時處理
xhr.ontimeout = function() {console.error('請求超時,請重試');
};xhr.onload = function() {if (xhr.status === 200) {console.log('請求成功');}
};xhr.send(null);
4.3 取消請求
通過abort()
方法取消正在進行的請求,觸發onabort
事件。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);xhr.onabort = function() {console.log('請求已取消');
};xhr.send(null);// 2秒后取消請求
setTimeout(() => {xhr.abort();
}, 2000);
五、跨域問題與解決方案
由于瀏覽器的同源策略(Same-Origin Policy),Ajax默認不允許請求不同域名、端口或協議的資源,否則會出現跨域錯誤。
5.1 同源策略的限制
同源指協議、域名、端口三者完全相同:
- 允許:
http://example.com
→http://example.com/api
(同源); - 禁止:
http://example.com
→https://example.com
(協議不同); - 禁止:
http://example.com
→http://api.example.com
(域名不同); - 禁止:
http://example.com:80
→http://example.com:8080
(端口不同)。
5.2 跨域解決方案
5.2.1 CORS(Cross-Origin Resource Sharing,推薦)
服務器端設置響應頭Access-Control-Allow-Origin
允許指定域名訪問:
// 服務器響應頭
Access-Control-Allow-Origin: https://example.com // 允許example.com跨域訪問
Access-Control-Allow-Origin: * // 允許所有域名(不推薦,不安全)
客戶端無需額外配置,直接發送請求即可:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.other-domain.com/data', true);
xhr.onload = function() {// 服務器已配置CORS,可正常接收響應
};
xhr.send(null);
5.2.2 JSONP(僅支持GET請求,兼容性好)
利用<script>
標簽不受同源策略限制的特性,通過動態創建<script>
標簽加載跨域腳本,執行回調函數傳遞數據。
客戶端示例:
// 定義回調函數(全局函數)
function handleJsonpData(data) {console.log('JSONP獲取的數據:', data);
}// 創建script標簽,加載跨域資源
const script = document.createElement('script');
// URL中指定回調函數名,服務器會返回"handleJsonpData(數據)"
script.src = 'https://api.other-domain.com/jsonp?callback=handleJsonpData';
document.body.appendChild(script);// 加載完成后移除script標簽
script.onload = function() {document.body.removeChild(script);
};
服務器返回數據格式(需配合):
// 服務器返回的內容(會被瀏覽器當作JS執行)
handleJsonpData({ name: '張三', age: 25 });
六、常見問題與避坑指南
6.1 跨域錯誤(No ‘Access-Control-Allow-Origin’ header)
原因:請求的域名與當前頁面域名不同,且服務器未配置CORS。
解決方案:
- 開發環境:使用代理服務器(如Webpack Dev Server的
proxy
配置); - 生產環境:服務器配置
Access-Control-Allow-Origin
響應頭; - 兼容舊瀏覽器:使用JSONP(僅GET請求)。
6.2 響應數據解析錯誤(JSON.parse失敗)
原因:服務器返回的不是合法JSON字符串(如HTML、錯誤信息)。
解決方案:
- 先檢查
xhr.responseText
的內容,確認是否為JSON; - 添加錯誤處理:
xhr.onload = function() {try {const data = JSON.parse(xhr.responseText);console.log('解析成功', data);} catch (error) {console.error('JSON解析失敗:', xhr.responseText);}
};
6.3 POST請求被瀏覽器轉為OPTIONS請求
原因:跨域POST請求且請求頭包含非簡單頭(如Content-Type: application/json
)時,瀏覽器會先發送預檢請求(OPTIONS),檢查服務器是否允許跨域。
解決方案:
- 服務器需處理OPTIONS請求,返回允許的請求方法、請求頭:
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400 // 預檢請求緩存時間(24小時)
Ajax的替代方案
Ajax徹底改變了網頁的交互方式,使前端從靜態展示邁向動態交互。核心價值在于異步數據交互,無需刷新頁面即可更新內容。
雖然XHR是Ajax的基礎,但現代開發中更常用以下方案:
- Fetch API:基于Promise的新一代網絡請求API,語法更簡潔;
- Axios:封裝了XHR的第三方庫,支持Promise、攔截器、取消請求等,簡化開發。
Fetch API示例(替代XHR):
fetch('https://api.example.com/data').then(response => {if (!response.ok) {throw new Error(`HTTP錯誤,狀態碼:${response.status}`);}return response.json(); // 解析JSON}).then(data => console.log('Fetch獲取數據:', data)).catch(error => console.error('請求失敗:', error));
若這篇內容幫到你,動動手指支持下!關注不迷路,干貨持續輸出!
ヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノ