http 請求系列
http request-01-XMLHttpRequest XHR 簡單介紹
http request-01-XMLHttpRequest XHR 標準
Ajax 詳解-01-AJAX(Asynchronous JavaScript and XML)入門介紹
Ajax XHR 的替代方案-fetch
Ajax XHR 的替代方案-fetch 標準
Ajax 的替代方案-axios.js
http 請求-04-promise 物件 + async/await
XHR 的官方學習資料 給出網址
以下是一些官方學習 XMLHttpRequest
(XHR) 的資源網址:
-
MDN Web Docs - XMLHttpRequest
- MDN XMLHttpRequest Documentation
- 這是最權威和詳細的 XHR 文件,提供了關於如何使用
XMLHttpRequest
的全面介紹,包括屬性、方法、事件和示例程式碼。
-
WhatWG - XMLHttpRequest Standard
- WhatWG XMLHttpRequest Standard
- WhatWG 的標準文件詳細描述了
XMLHttpRequest
的規範和實現細節,是瞭解其正式標準的良好資源。
-
W3C - XMLHttpRequest Level 2 Specification
- W3C XMLHttpRequest Level 2
- W3C 的規範文件提供了
XMLHttpRequest
Level 2 的詳細描述,包括新增的功能和改進。
這些資源將幫助你深入理解 XMLHttpRequest
的功能、用法和規範。
XHR 是什麼?
XMLHttpRequest
(XHR)是一個用於在客戶端和伺服器之間進行非同步 HTTP 請求的 API,廣泛用於動態更新網頁內容,而無需重新載入整個頁面。
儘管它最初是為了處理 XML 資料而設計的,但它現在支援多種資料格式,並已成為 Web 開發中重要的工具。
1. 基本概念
XMLHttpRequest
提供了在客戶端(如瀏覽器)與伺服器之間進行非同步通訊的能力,使得網頁可以在不重新載入頁面的情況下更新內容。
它的主要用途包括動態載入資料、提交表單以及與伺服器進行實時互動。
2. 核心方法和屬性
2.1 建立請求
const xhr = new XMLHttpRequest();
2.2 配置請求
- open(method, url, async, user, password): 初始化請求。
method
: HTTP 方法(如GET
、POST
)。url
: 請求的 URL。async
: 是否非同步(true
或false
)。user
和password
: 可選的身份驗證資訊。
xhr.open('GET', 'https://example.com/data', true);
2.3 傳送請求
- send(body): 傳送請求。
body
引數用於傳送資料(對於GET
請求,通常為空)。
xhr.send();
2.4 事件處理
- onload: 請求成功完成時觸發。
- onerror: 請求失敗時觸發。
- onprogress: 請求進度更新時觸發(適用於進度監控)。
- onabort: 請求被取消時觸發。
- onreadystatechange: 請求狀態改變時觸發。
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.responseText);
} else {
console.error('Request failed with status:', xhr.status);
}
};
xhr.onerror = function() {
console.error('Request error');
};
2.5 重要屬性
- readyState: 請求的當前狀態(0: UNSENT, 1: OPENED, 2: HEADERS_RECEIVED, 3: LOADING, 4: DONE)。
- status: HTTP 響應狀態碼(如 200、404、500)。
- statusText: 響應狀態文字。
- responseText: 響應的文字內容。
- responseXML: 響應的 XML 文件(如果
Content-Type
是application/xml
或text/xml
)。 - response: 根據響應型別(如
ArrayBuffer
、Blob
)返回的響應資料。
3. 使用示例
3.1 簡單 GET 請求
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onload = function() {
if (xhr.status === 200) {
console.log('Response:', xhr.responseText);
} else {
console.error('Error:', xhr.status, xhr.statusText);
}
};
xhr.send();
3.2 POST 請求
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.onload = function() {
if (xhr.status === 201) {
console.log('Created:', xhr.responseText);
} else {
console.error('Error:', xhr.status, xhr.statusText);
}
};
const data = JSON.stringify({ title: 'foo', body: 'bar', userId: 1 });
xhr.send(data);
3.3 進度監控
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log('Progress:', percentComplete.toFixed(2) + '%');
}
};
xhr.onload = function() {
if (xhr.status === 200) {
console.log('Response:', xhr.responseText);
} else {
console.error('Error:', xhr.status, xhr.statusText);
}
};
xhr.send();
4. 優缺點
4.1 優點
- 廣泛支援: 相容大多數瀏覽器,包括較早版本。
- 靈活性: 支援多種 HTTP 方法和請求體格式。
- 進度監控: 能夠監控請求的進度和狀態變化。
4.2 缺點
- 複雜性: 處理非同步操作和錯誤處理可能比較複雜,特別是巢狀的回撥函式(“回撥地獄”)。
- 現代替代品: 比如
fetch
API 提供了更簡潔的語法和更強大的功能,例如流處理和更好的錯誤處理。
5. 現代替代
XMLHttpRequest
的一些功能和用途已經被更現代的 fetch
API 所取代。fetch
提供了更簡潔的語法、支援 Promise 和流處理,使得非同步操作和錯誤處理更為直觀。
XHR 為什麼需要?解決了什麼問題
XMLHttpRequest
(XHR) 是一種用於在瀏覽器和伺服器之間進行非同步通訊的 API。它在 Web 開發中解決了多個關鍵問題,特別是在使用者體驗和動態網頁更新方面。
以下是 XMLHttpRequest
需要的原因及其解決的問題:
1. 頁面非同步更新
問題
- 傳統的網頁請求: 每次需要從伺服器獲取新資料或提交資料時,整個頁面必須重新載入。這種方式會導致使用者體驗不流暢,頁面重新整理較慢。
解決方案
- XHR 的非同步請求: 允許網頁在不重新載入整個頁面的情況下,從伺服器獲取資料並更新部分頁面內容。這使得網頁可以實現區域性更新,而不是每次都重新整理整個頁面,從而提高了使用者體驗和響應速度。
2. 提高使用者體驗
問題
- 頁面停頓: 在傳統的同步請求中,使用者必須等待整個請求和響應過程完成,這可能導致頁面停頓或凍結。
解決方案
- 非同步處理:
XMLHttpRequest
透過非同步處理請求,允許瀏覽器在發出請求時繼續執行其他操作,不會阻塞使用者介面的互動。這樣,使用者可以繼續與網頁進行互動,而不會受到請求等待的影響。
3. 動態內容載入
問題
- 靜態網頁內容: 在沒有非同步請求的情況下,網頁內容通常是靜態的,所有內容都在頁面載入時獲取。
解決方案
- 動態內容載入: 透過
XMLHttpRequest
,網頁可以在執行時動態載入資料,並根據需要更新內容。比如,使用者滾動到頁面底部時自動載入更多資料(如無限滾動),或者基於使用者輸入實時更新搜尋結果。
4. 後臺資料處理
問題
- 使用者互動時的資料提交: 使用者在填寫表單時,資料提交通常會導致頁面重新載入,影響使用者體驗。
解決方案
- 表單提交: 使用
XMLHttpRequest
可以在不重新整理頁面的情況下提交表單資料。這使得使用者可以在不離開當前頁面的情況下完成資料提交和處理。
5. 區域性更新和請求管理
問題
- 整體更新難度: 如果需要對部分頁面內容進行更新,傳統方法通常需要複雜的頁面過載和資料處理。
解決方案
- 區域性更新:
XMLHttpRequest
允許透過指定的 URL 和請求方法,只更新頁面的某一部分內容。這簡化了區域性更新的實現,並減少了對伺服器的負擔。
6. 進度監控
問題
- 缺乏反饋: 在傳統請求中,使用者無法獲得請求進度的資訊(如正在下載的進度)。
解決方案
- 進度事件:
XMLHttpRequest
提供了onprogress
事件,使得開發者可以實時監控請求的進度,並向使用者提供反饋,例如顯示下載進度條。
7. 與其他技術的相容性
問題
- 舊版瀏覽器支援: 在
fetch
API 出現之前,許多舊版瀏覽器不支援現代的 HTTP 請求 API。
解決方案
- 相容性:
XMLHttpRequest
作為較早的標準,得到了廣泛的瀏覽器支援,包括舊版瀏覽器。這使得它在需要相容舊版瀏覽器的應用中仍然非常重要。
XHR 的適用場景,優缺點
XMLHttpRequest
(XHR)在 Web 開發中有一些特定的適用場景,以及它的優點和缺點。
以下是一些實際應用場景和它們的優缺點,用更接地氣的方式來解釋:
適用場景
-
動態內容更新
- 場景: 當你希望在使用者與網頁互動時,動態更新頁面的一部分內容,例如載入評論、文章或產品列表,而不需要重新載入整個頁面。
- 例子: 社交媒體平臺上的帖子載入,電商網站上的產品篩選。
-
非同步表單提交
- 場景: 當使用者填寫表單並提交資料時,你希望在後臺處理這些資料,而不重新整理整個頁面。
- 例子: 使用者在評論框中輸入內容並提交,資料直接上傳到伺服器,頁面不會過載。
-
區域性資料重新整理
- 場景: 需要重新整理網頁的某個部分的資料,而不是整個頁面。例如,實時更新價格或天氣資訊。
- 例子: 監控儀表板上更新伺服器狀態,新聞網站上實時更新新聞頭條。
-
進度反饋
- 場景: 需要監控和展示檔案上傳或下載的進度,讓使用者知道操作的進展。
- 例子: 檔案上傳表單,下載大檔案時顯示進度條。
-
舊版瀏覽器相容
- 場景: 如果你的應用需要支援舊版瀏覽器,它可能不支援現代的
fetch
API,但支援XMLHttpRequest
。 - 例子: 針對使用老舊裝置或瀏覽器的使用者群體的應用。
- 場景: 如果你的應用需要支援舊版瀏覽器,它可能不支援現代的
優點
-
廣泛支援
- 優點: 幾乎所有的瀏覽器都支援
XMLHttpRequest
,包括許多舊版瀏覽器。 - 實際感受: 你不需要擔心使用者的瀏覽器是否支援,因為它幾乎能在所有環境中工作。
- 優點: 幾乎所有的瀏覽器都支援
-
靈活性
- 優點: 支援多種 HTTP 方法(GET、POST、PUT、DELETE 等),並且能夠處理不同格式的響應資料。
- 實際感受: 可以用來做各種各樣的請求,比如從伺服器獲取 JSON 資料或傳送表單資料。
-
進度監控
- 優點: 提供
onprogress
事件,可以監控請求的進度。 - 實際感受: 你可以給使用者提供下載或上傳的實時進度,提升使用者體驗。
- 優點: 提供
缺點
-
複雜性
- 缺點: 處理非同步請求和響應可能會很複雜,尤其是在巢狀回撥函式(“回撥地獄”)的情況下。
- 實際感受: 編寫程式碼時可能會變得混亂,不容易維護。
-
沒有內建的 Promise 支援
- 缺點: 不像
fetch
API,XMLHttpRequest
預設不支援 Promise,處理非同步操作時需要使用回撥函式。 - 實際感受: 需要額外的工作來處理非同步操作,程式碼可能不夠簡潔。
- 缺點: 不像
-
較少的功能擴充套件
- 缺點: 與現代 API 比如
fetch
相比,XMLHttpRequest
在流處理和功能擴充套件方面有所限制。 - 實際感受: 如果需要更高階的功能,比如流式處理大檔案,
XMLHttpRequest
可能無法滿足需求。
- 缺點: 與現代 API 比如
XHR 的使用最佳實踐
使用 XMLHttpRequest
(XHR) 時,遵循一些最佳實踐可以幫助你寫出更高效、可靠和可維護的程式碼。以下是一些實際的最佳實踐:
1. 使用非同步請求
- 實踐: 總是將
XMLHttpRequest
的async
引數設定為true
,以便非同步處理請求。 - 理由: 非同步請求不會阻塞使用者介面,提高了使用者體驗。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);
xhr.send();
2. 處理請求狀態變化
- 實踐: 使用
onreadystatechange
事件來處理請求的不同狀態。確保檢查readyState
和status
屬性來確定請求是否成功完成。 - 理由:
readyState
提供了請求的當前狀態,status
表示 HTTP 響應狀態碼,幫助你正確處理響應或錯誤。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { // DONE
if (xhr.status === 200) {
console.log('Response:', xhr.responseText);
} else {
console.error('Error:', xhr.status, xhr.statusText);
}
}
};
xhr.send();
3. 設定適當的請求頭
- 實踐: 根據需要設定請求頭(例如
Content-Type
)。如果你傳送 JSON 資料,確保設定Content-Type
為application/json
。 - 理由: 請求頭可以影響伺服器如何處理請求體,確保請求和響應資料格式的正確性。
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
const data = JSON.stringify({ key: 'value' });
xhr.send(data);
4. 處理錯誤和超時
- 實踐: 使用
onerror
事件處理網路錯誤,使用ontimeout
處理超時情況。設定超時時間以防止請求掛起過久。 - 理由: 錯誤處理可以提供更好的使用者反饋和恢復機制,而超時處理可以避免長時間等待無響應的請求。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);
xhr.timeout = 5000; // 設定超時時間為 5000 毫秒
xhr.ontimeout = function() {
console.error('Request timed out');
};
xhr.onerror = function() {
console.error('Request error');
};
xhr.onload = function() {
if (xhr.status === 200) {
console.log('Response:', xhr.responseText);
}
};
xhr.send();
5. 監控進度
- 實踐: 使用
onprogress
事件來監控請求的進度,尤其是處理大檔案上傳或下載時。 - 理由: 進度反饋可以改善使用者體驗,讓使用者瞭解操作的進展。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/largefile', true);
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
console.log('Progress:', percentComplete.toFixed(2) + '%');
}
};
xhr.onload = function() {
if (xhr.status === 200) {
console.log('File downloaded successfully');
}
};
xhr.send();
6. 避免回撥地獄
- 實踐: 使用清晰的回撥結構或考慮使用
Promises
(如果需要相容性,可以用Promise
封裝 XHR)。雖然 XHR 本身不支援Promise
,但你可以建立自己的封裝。 - 理由: 清晰的回撥結構或使用
Promise
可以提高程式碼的可讀性和可維護性。
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (xhr.status === 200) {
resolve(xhr.responseText);
} else {
reject(new Error(`Request failed with status ${xhr.status}`));
}
};
xhr.onerror = function() {
reject(new Error('Network error'));
};
xhr.send();
});
}
// 使用
fetchData('https://example.com/data')
.then(response => console.log('Response:', response))
.catch(error => console.error('Error:', error));
7. 處理不同資料格式
- 實踐: 根據伺服器響應的
Content-Type
處理資料。例如,如果響應是 JSON 格式,則呼叫responseText
並使用JSON.parse
解析。 - 理由: 正確處理不同的資料格式確保資料解析的準確性。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);
xhr.onload = function() {
if (xhr.status === 200) {
const contentType = xhr.getResponseHeader('Content-Type');
if (contentType.includes('application/json')) {
const data = JSON.parse(xhr.responseText);
console.log('JSON data:', data);
} else {
console.log('Response:', xhr.responseText);
}
}
};
xhr.send();
8. 保持程式碼簡潔
- 實踐: 儘量保持 XHR 請求程式碼簡潔,避免過多的巢狀和複雜邏輯。封裝常用邏輯為函式可以提高可重用性。
- 理由: 簡潔的程式碼更易於維護和理解。
function createRequest(method, url, callback) {
const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
callback(null, xhr.responseText);
} else {
callback(new Error(`Request failed with status ${xhr.status}`));
}
};
xhr.onerror = function() {
callback(new Error('Network error'));
};
xhr.send();
}
// 使用
createRequest('GET', 'https://example.com/data', (error, response) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Response:', response);
}
});
總結
遵循這些最佳實踐可以幫助你在使用 XMLHttpRequest
時編寫更高效、可靠和易於維護的程式碼。
雖然 fetch
API 提供了更現代的介面,但瞭解和掌握 XMLHttpRequest
仍然在許多情況下很重要,尤其是在處理相容性問題時。