當前位置: 妍妍網 > 碼農

前端請求大比拼:Fetch、Axios、Ajax、XHR

2024-04-02碼農

全文約 10000 字,預計 閱讀 需要 30 分鐘。

當涉及前端網路請求時,有許多工具/技術可供選擇,包括 Fetch、Axios、Ajax 和 XHR 等。這些技術在發送和處理HTTP請求方面提供了不同的功能和方法。本文將深入探討這些技術的特點、優勢和用法,幫你更好地理解並選擇最適合計畫需求的技術。

1

基本概念

Summer IS HERE

Fetch、Axios、Ajax 和XHR都是前端用於發送HTTP請求的工具或技術:

  • Fetch :一種現代化的網路請求方法,透過使用 Promise 處理異步操作,簡潔而直觀地發送HTTP請求、處理響應,並支持各種功能和API,如設定請求頭、傳遞參數、處理流數據、上傳下載檔等。

  • Axios :一個基於Promise的現代化HTTP客戶端,是目前最流行的 HTTP 客戶端,可以在瀏覽器和Node.js環境中發送HTTP請求,並具有攔截請求和響應、支持並行請求、提供豐富的API等功能。

  • Ajax :透過在瀏覽器和伺服器之間進行異步通訊,實作部份頁面更新和動態互動,提升使用者體驗;可以在不重新載入整個頁面的情況下,透過JavaScript發送HTTP請求到伺服器,並處理伺服器返回的數據;減少頻寬消耗,提高頁面載入速度;提高使用者互動性,實作更多的動態效果和即時更新。

  • XHR :一種在瀏覽器中用於與伺服器進行異步通訊的API,透過發送HTTP請求並處理伺服器返回的數據,實作異步獲取各種格式的數據(如XML、JSON、HTML等),以實作頁面的無重新整理更新和動態互動。

  • 下面就來看看這些技術都是怎麽用的,以及都有什麽特點!

    2

    XHR

    Summer IS HERE

    XMLHttpRequest 是一個內建的 JavaScript 物件,XMLHttpRequest(XHR)物件用於與伺服器互動。透過 XMLHttpRequest 可以在不重新整理頁面的情況下請求特定 URL,獲取數據。這允許網頁在不影響使用者操作的情況下,更新頁面的局部內容。

    XMLHttpRequest 在 AJAX 編程中被大量使用。盡管名稱包含XML,XMLHttpRequest 也可以用於獲取任何型別的數據,而不僅僅是 XML。它甚至支持 HTTP 以外的協定(包括 file:// FTP )。

    XMLHttpRequest 存在一些缺點:

  • 語法復雜性 :使用原始的 XMLHttpRequest 進行復雜的 AJAX 請求需要編寫更多的程式碼,並手動處理狀態管理、錯誤處理等方面的邏輯。相比之下,Axios 和 Fetch API 提供了更簡單和直觀的語法,使得發送和處理 HTTP 請求更加方便。

  • 功能限制 :XHR 提供的功能相對較少,需要手動設定請求頭、處理超時、取消請求等。而 Axios 和 Fetch API 提供了更豐富的功能,如攔截請求和響應、自動轉換數據格式、請求取消等。

  • XSRF(跨站請求偽造)保護 :在 Axios 中,可以透過設定 withCredentials 選項來自動處理 XSRF 保護。然而,在 XMLHttpRequest 和 Fetch API 中,需要手動設定請求頭來實作類似的保護。

  • 錯誤處理 :XHR 的錯誤處理較為繁瑣,需要在回呼函式中進行錯誤判斷。而 Axios 和 Fetch API 使用 Promise 和 async/await 語法,能夠更便捷地處理請求和響應的錯誤。

  • 僅限於瀏覽器環境 :XMLHttpRequest 是瀏覽器提供的 API,因此只能在瀏覽器環境中使用,無法在其他環境中(如伺服器端)直接使用。

  • Summer

    請求步驟

    使用 XMLHttpRequest 發送請求的步驟如下:

    1. 建立 XMLHttpRequest 物件:

    let xhr = new XMLHttpRequest();

    1. 設定請求參數:

    xhr.open('GET','https://example.com/api/data', true);

    1. 設定請求頭(可選):

    xhr.setRequestHeader('Content-Type','application/json');

    1. 監聽狀態變化:

    xhr.onreadystatechange=()=>{
    if(xhr.readyState === 4){
    if(xhr.status === 200){
    // 請求成功,處理響應
    console.log(xhr.responseText);
    }else{
    // 請求失敗
    console.error('請求失敗');
    }
    }
    };

    1. 發送請求:

    xhr.send();

    完整程式碼如下:

    var xhr =newXMLHttpRequest();
    xhr.open('GET','https://api.example.com/data', true);
    xhr.onreadystatechange=()=>{
    if(xhr.readyState === 4){
    if(xhr.status === 200){
    // 請求成功,處理響應
    console.log(xhr.responseText);
    }else{
    // 請求失敗
    console.error('請求失敗');
    }
    }
    };
    xhr.send();

    這裏建立了一個 XMLHttpRequest 物件,並使用 open() 方法設定了一個GET請求型別和URL。然後,透過監聽 onreadystatechange 事件來判斷請求的狀態並處理響應。當 readyState 為4時,表示請求已完成,此時可以透過 status 內容判斷請求是否成功(200表示成功)。如果成功,可以透過 responseText 內容獲取伺服器返回的數據進行處理。如果失敗,將到控制台輸出錯誤資訊。

    Summer

    open

    XMLHttpRequest 的 open() 方法用於初始化一個請求。 open() 方法接受三個必填參數和一個可選參數,它們是:

    1. method : 表示請求的 HTTP 方法,例如 GET、POST、PUT 等。

    xhr.open("GET","https://example.com/api/data", true);

    1. url : 表示請求的 URL 地址。

    xhr.open("GET","https://example.com/api/data", true);

    1. async : 表示請求是否異步執行,即是否使用異步模式。預設為 true ,表示異步執行;f alse 表示同步執行。

    javascriptCopy Codexhr.open("GET", "https://example.com/api/data", true);

    1. username (可選): 表示用於進行 HTTP 認證的使用者名稱。

    xhr.open("GET", "https://example.com/api/data", true, "username");

    1. password (可選): 表示用於進行 HTTP 認證的密碼。

    xhr.open("GET", "https://example.com/api/data", true, "username", "password");

    綜合起來, open() 方法的完整語法如下:

    xhr.open(method, url, async, username, password);

    Summer

    請求頭和響應頭

    可以使用 setRequestHeader() 方法設定 XMLHttpRequest 的請求頭。這個方法接受兩個參數:頭欄位的名稱和值。

    xhr.setRequestHeader("Content-Type","application/json");
    xhr.setRequestHeader("Authorization","Bearer token123");

    這裏使用 setRequestHeader() 方法設定了兩個請求頭: Content-Type Authorization 。第一個參數是頭欄位的名稱,第二個參數是頭欄位的值。

    可以使用 getResponseHeader() 方法或者 getAllResponseHeaders() 方法來獲取 XMLHttpRequest 的響應頭。

  • getResponseHeader() :透過指定頭欄位的名稱,可以獲取指定的響應頭欄位的值。

  • const contentType = xhr.getResponseHeader("Content-Type");

    這裏使用 getResponseHeader() 方法獲取了名為 Content-Type 的響應頭欄位的值。

  • getAllResponseHeaders() ** **:該方法返回一個包含所有響應頭資訊的字串。

  • const headers = xhr.getAllResponseHeaders();

    這裏使用 getAllResponseHeaders() 方法獲取了所有響應頭資訊,並將其儲存在名為 headers 的變量中。

    這裏返回的 headers 是一個包含所有響應頭資訊的字串。該字串中每一行表示一個響應頭欄位,具有以下形式:

    HeaderName: HeaderValue

    例如,如果響應頭中包含 Content-Type Authorization 欄位,那麽返回的 headers 字串可能如下所示:

    Content-Type: application/json
    Authorization: Bearer token123

    可以使用適當的方法(如字串解析)將這個字串進行進一步處理,以獲取特定的響應頭欄位的名稱和值。

    註意,要在呼叫 open() 方法之後、發送請求之前使用 setRequestHeader() 方法來設定請求頭,以確保設定能夠生效。同樣,要在接收到響應之後才能使用 getResponseHeader() getAllResponseHeaders() 來獲取響應頭資訊。

    Summer

    readyState

    上面範例中的 readyState 是 XMLHttpRequest 物件的一個內容,用於表示請求的狀態。該內容有以下五種可能的取值:

    1. 0 (未初始化) : XMLHttpRequest 物件已建立,但尚未呼叫 open 方法。

    2. 1 (載入中) : open 方法已呼叫,但尚未呼叫 send 方法。

    3. 2 (載入完成) : s end 方法已呼叫,並且響應頭和響應狀態已經可用。

    4. 3 (互動中) : 正在接收響應數據,此時部份響應內容可能已經可以存取了。

    5. 4 (完成) : 響應數據接收完成,整個請求過程已經完全結束。

    通常情況下,我們主要關註 readyState 為 4 的狀態,即請求完成狀態。在這個狀態下,我們可以透過檢查 status 內容來獲取請求的結果(比如響應狀態碼),並透過 responseText responseXML 內容來獲取伺服器返回的數據。

    註意,readyState 內容是唯讀的,我們不能直接修改它的值。它會在請求過程中自動更新,我們可以透過監聽 readystatechange 事件來進行相應的處理。

    Summer

    status

    status 是 XMLHttpRequest 物件的一個內容,用於表示 HTTP 狀態碼。 HTTP 狀態碼是伺服器對請求處理的結果進行響應的標準化數位程式碼。常見的一些 HTTP 狀態碼包括:

  • 200 OK :表示請求成功並返回所請求的數據。

  • 201 Created :表示請求成功並在伺服器上建立了新資源。

  • 204 No Content :表示請求成功,但響應中無返回的內容。

  • 400 Bad Request :表示請求有語法錯誤或參數錯誤,伺服器無法理解。

  • 401 Unauthorized :表示請求未經授權,需要使用者進行身份驗證。

  • 403 Forbidden :表示伺服器拒絕請求,通常是因為請求的資源沒有存取許可權。

  • 404 Not Found :表示請求的資源不存在。

  • 500 Internal Server Error :表示伺服器內部發生錯誤,無法完成請求。

  • 在使用 XMLHttpRequest 發送請求後,可以透過檢查 status 內容來獲取伺服器對請求的響應狀態碼,並根據不同的狀態碼進行相應的處理。

    Summer

    事件內容

    XMLHttpRequest (XHR) 物件具有以下常用的事件內容:

    1. onreadystatechange : 當 readyState 內容發生變化時觸發該事件。可以使用 xhr.onreadystatechange 內容來指定處理狀態變化的回呼函式。在每次狀態變化時都會觸發該事件,可以透過檢查 xhr.readyState 內容來確定當前的狀態。

    xhr.onreadystatechange=()=>{
    if(xhr.readyState === 4){
    // 請求已完成
    if(xhr.status === 200){
    // 請求成功
    }else{
    // 請求失敗
    }
    }else{
    // 請求進行中
    }
    };

    1. onload: 當請求成功完成並且響應數據完全載入時觸發該事件。可以使用 xhr.onload 內容來指定處理成功載入的回呼函式。通常在這個事件中獲取和處理響應數據。

    xhr.onload=()=>{
    // 獲取和處理響應數據
    const responseData =JSON.parse(xhr.responseText);
    // 其他操作...
    };

    1. onerror : 當請求發生錯誤時觸發該事件。可以使用 xhr.onerror 內容來指定處理錯誤的回呼函式。常見的錯誤包括網路錯誤、無法完成請求等。

    xhr.onerror=()=>{
    // 處理錯誤邏輯
    };

    1. onprogress : 在數據傳輸過程中持續觸發,用於追蹤請求的進度。可以使用 xhr.onprogress 內容來指定處理進度的回呼函式。

    xhr.onprogress=(event)=>{
    // 處理進度邏輯
    };

    1. ontimeout : 當請求超時時觸發該事件。可以使用 xhr.ontimeout 內容來指定處理超時的回呼函式。

    xhr.ontimeout=()=>{
    // 處理超時邏輯
    };

    Summer

    responseType

    responseType 是 XMLHttpRequest 物件的內容,用於指定響應的數據型別。它決定了如何解析從伺服器返回的響應數據。 常見的 responseType 值包括:

    1. "" (預設值) : 表示響應的數據型別是字串。

    xhr.responseType ="";

    1. "text" : 表示響應的數據型別是字串。

    xhr.responseType ="text";

    1. "json" : 表示響應的數據型別是 JSON 物件,會自動將響應數據解析為 JavaScript 物件。

    xhr.responseType ="json";

    1. "document" : 表示響應的數據型別是 XML 文件物件,會自動將響應數據解析為 XML 文件物件。

    xhr.responseType ="document";

    1. "arraybuffer" : 表示響應的數據型別是 ArrayBuffer 物件,適用於二進制數據的傳輸和處理。

    xhr.responseType ="arraybuffer";

    1. "blob" : 表示響應的數據型別是 Blob 物件,適用於檔下載等場景。

    xhr.responseType ="blob";

    透過設定不同的 responseType 值,可以根據需要獲取不同型別的響應數據。註意,在設定 responseType 之前,最好在呼叫 open 方法之後、發送請求之前設定,以確保設定生效。

    3

    Ajax

    Summer IS HERE

    AJAX(Asynchronous JavaScript and XML,異步 JavaScript 和 XML)是一種使用現有的網頁技術來建立異步請求和更新頁面內容的方法。Ajax 本身不是一種技術,而是一種將一些現有技術結合起來使用的方法,包括:HTML 或 XHTML、CSS、JavaScript、DOM、XML、XSLT、以及最重要的 XMLHttpRequest 物件。

    當使用結合了這些技術的 Ajax 模型以後,網頁套用能夠快速地將增量更新呈現在使用者介面上,而不需要多載(重新整理)整個頁面。這使得程式能夠更快地回應使用者的操作。Ajax 最吸引人的特性是它的「異步」性質,這意味著它可以與伺服器通訊、交換數據並更新頁面,而無需重新整理頁面。

    Ajax 是一種使用瀏覽器提供的 XMLHttpRequest 物件實作的技術,用於在不重新整理整個頁面的情況下進行異步請求和更新頁面內容。 可以說 Ajax 是基於瀏覽器提供的 XMLHttpRequest 物件來實作的。

    以下是基於原生 JavaScript 的 AJAX 請求程式碼範例:

    // 建立 XMLHttpRequest 物件
    const xhr =newXMLHttpRequest();
    // 指定請求的方法和 URL
    xhr.open('GET','api_url', true);// 第三個參數 true 表示異步請求
    // 設定請求頭(如果需要)
    xhr.setRequestHeader('Content-Type','application/json');// 根據實際需求設定請求頭
    // 註冊一個回呼函式來處理響應
    xhr.onreadystatechange=function(){
    if(xhr.readyState === 4 && xhr.status === 200){
    const response =JSON.parse(xhr.responseText);// 處理響應數據
    // 在這裏執行相應的操作
    console.log(response);
    }
    };
    // 發送請求
    xhr.send();

    雖然 AJAX 是一種強大的技術,但相對於 Axios 和 Fetch API,它有以下一些缺點:

  • 相容性問題 :AJAX 的相容性相對較低,尤其在舊版本的瀏覽器中可能會出現問題。而 Axios 和 Fetch API 使用了更現代的 JavaScript 特性,具有更好的相容性。

  • 程式碼冗余 :使用原生的 AJAX 需要編寫較多的程式碼來處理不同的狀態碼、錯誤處理以及請求的拼裝等。而 Axios 和 Fetch API 提供了更簡潔和易用的介面,減少了程式碼冗余。

  • 缺乏預設配置 :AJAX 不提供預設的全域配置,如請求和響應攔截器、統一的錯誤處理等。而 Axios 和 Fetch API 支持全域配置,並且提供了更方便的攔截器機制。

  • 功能限制 :AJAX 在處理跨域請求時需要註意添加額外的處理,比如設定 CORS 頭部資訊或者使用 JSONP。而 Axios 和 Fetch API 提供了更直接的方式來處理跨域請求。

  • 可讀性較差 :由於 AJAX 使用的是回呼函式來處理異步請求,可能會導致程式碼邏輯比較復雜,可讀性較差。而 Axios 和 Fetch API 使用的是 Promise 或 async/await,使程式碼結構更加清晰易讀。

  • 4

    Fetch

    Summer IS HERE

    Fetch 是一種用於進行網路請求的現代 JavaScript API。它提供了一種簡單、靈活且功能強大的方式,用於從伺服器獲取資源並處理響應。

    Fetch API 在瀏覽器中原生支持,並且以 Promise 為基礎,使得異步請求更加直觀和易用。使用 Fetch API,可以執行各種型別的請求(如 GET、POST、PUT、DELETE 等),發送請求時可以設定請求頭、請求參數,以及處理響應數據。

    與傳統的 AJAX 相比,Fetch API 具有以下優點:

  • Promise 支持 :Fetch API 使用 Promise 物件來處理異步操作,使得處理異步請求的流程更加清晰、易於閱讀和編寫。

  • 更簡潔的 API :Fetch API 提供了一個簡潔的 API,使發送請求變得更加直觀和簡單,同時提供了豐富的配置選項(如設定請求頭、請求參數等)。

  • 內建的 JSON 解析 :在處理響應時,Fetch API 內建了對 JSON 數據的解析,無需手動進行解析操作。

  • 更好的錯誤處理 :Fetch API 使用了更全面的錯誤處理機制,允許透過檢查響應狀態碼來確定請求是否成功,並以不同的方式處理錯誤。

  • Summer

    fetch()

    Fetch API 提供了一個全域的 fetch() 方法,該方法提供了一種簡單、邏輯的方式來透過網路異步獲取資源。

    fetch() 方法的語法如下:

    fetch(url, options)
    .then(response =>{
    // 在這裏處理響應
    })
    .catch(error =>{
    // 在這裏處理錯誤
    });

    這裏有兩個參數:

  • url :請求的 URL 地址。

  • options (可選):一個包含請求選項的物件,可以指定請求的方法(method)、請求頭(headers)、請求體(body)等。

  • 註意, fetch() 預設使用的是 GET 請求,如果需要使用其他方法(如 POST、PUT 等),需要透過 options 參數進行設定。

    fetch() 方法返回一個 Promise 物件,可以使用 .then() 方法來處理成功的響應,使用 .catch() 方法來處理錯誤的情況。

  • .then() 中,可以存取到 response 物件,進一步處理響應的內容。

  • .catch() 中,我們可以存取到 error 物件,用於處理請求過程中的任何錯誤。

  • options 物件包含的內容如下:

    {
    method:'POST',// *GET, POST, PUT, DELETE等
    mode:'cors',// no-cors, *cors, same-origin
    cache:'no-cache',// *default, no-cache, reload, force-cache, only-if-cached
    credentials:'same-origin',// include, *same-origin, omit
    headers:{
    'Content-Type':'application/json'
    },
    redirect:'follow',// manual, *follow, error
    referrerPolicy:'no-referrer',// no-referrer, *client
    body:JSON.stringify(data)
    // body 數據型別必須與 "Content-Type" 請求頭匹配
    }

  • method :請求方法,例如 GET、POST、PUT、DELETE 等。

  • mode :請求模式,可以是 no-cors、*cors、same-origin 等。

  • cache :緩存模式,可以是 default、no-cache、reload、force-cache、only-if-cached 等。

  • credentials :請求的憑證模式,可以是 include、*same-origin、omit 等。

  • headers :請求頭物件,用於設定請求頭的鍵值對。

  • redirect :重新導向模式,可以是 manual、*follow、error 等。

  • referrerPolicy :參照頁面私密設定,可以是 no-referrer、*client 等。

  • body :請求體數據,必須與 "Content-Type" 請求頭指定的數據型別匹配。在範例中,使用 JSON.stringify() 將數據轉換為 JSON 字串。

  • Summer

    response

    一旦獲取到響應(Response),返回的物件包含以下內容:

  • response.body :一個簡單的 getter,提供了響應內容的可讀流(ReadableStream)。

  • response.bodyUsed :一個布爾值,用於記錄響應體是否已經被使用過。

  • response.headers :與響應相關聯的頭部資訊物件。

  • response.ok :一個布爾值,指示響應是否成功。

  • response.redirected :指示響應是否是重新導向結果的布爾值。

  • response.status :響應的狀態碼。

  • response.statusText :與狀態碼對應的狀態訊息。

  • response.type :響應的型別。

  • response.url :響應的 URL。

  • 我們可以使用 response.type 來確定響應的型別,並根據不同的型別采取相應的處理方法:

    fetch(url)
    .then(response =>{
    // 檢查響應狀態碼
    if(!response.ok){
    thrownewError('Network response was not ok');
    }
    // 定義一個響應型別與解析方法的對映關系
    const responseTypes =newMap([
    ['json',()=> response.json()],
    ['text',()=> response.text()],
    ['formData',()=> response.formData()],
    ['blob',()=> response.blob()],
    ['arrayBuffer',()=> response.arrayBuffer()]
    ]);
    // 根據響應型別選擇相應的解析方法
    const parser = responseTypes.get(response.type);
    if(parser){
    returnparser();
    }else{
    thrownewError('Unsupported response type');
    }
    })
    .then(data =>{
    // 處理數據
    console.log(data);
    })
    .catch(error =>{
    // 處理錯誤情況
    console.error('Error:', error);
    });

    Response 物件提供了 5 個方法,用於從 HTTP 響應中獲取不同型別的數據:

  • response.json() :將響應體解析為 JSON 物件。如果響應的 Content-Type 是 application/json ,則使用此方法。

  • response.text() :將響應體解析為文本字串。如果響應的 Content-Type 是純文本型別,如 text/plain 或 text/html,則使用此方法。

  • response.formData() :將響應體解析為 FormData 物件。如果響應的 Content-Type 是 multipart/form-data,則使用此方法。FormData 通常用於上傳檔或送出表單數據。

  • response.blob() :將響應體解析為 Blob 物件。Blob 物件表示二進制大物件,可以是影像、音訊、視訊等型別的數據。

  • response.arrayBuffer() :將響應體解析為 ArrayBuffer 物件。ArrayBuffer 是一種表示二進制數據的固定長度緩沖區。

  • 這些方法返回一個 Promise,當解析完成時,Promise 將被解析為相應的數據型別。

    Summer

    請求頭和響應頭

    fetch 函式的請求頭包含在發起 HTTP 請求時發送給伺服器的資訊,用於傳遞額外的參數和配置。可以使用 headers 物件來設定和操作請求頭。常見的請求頭欄位包括:

  • Content-Type :指定請求體的格式型別,如 application/json application/x-www-form-urlencoded 等。

  • Authorization :用於身份驗證,通常與 Token 或使用者名稱密碼一起使用。

  • Accept :指定客戶端所能接受的響應數據型別。

  • User-Agent :標識發起請求的使用者代理(瀏覽器或應用程式)的資訊。

  • 在 fetch 函式中可以透過第二個參數進行配置,其中可以指定請求頭:

    fetch(url,{
    method:'GET',
    headers:{
    'Content-Type':'application/json',
    'Authorization':'Bearer token123'
    }
    })
    .then(response =>{
    // 處理響應
    })
    .catch(error =>{
    // 處理錯誤
    });

    響應頭是伺服器在響應 HTTP 請求時發送給客戶端的頭部資訊。可以透過 Response 物件的 headers 內容存取響應頭。常見的響應頭欄位包括:

  • Content-Type :指定響應體的格式型別。

  • Set-Cookie :設定或修改客戶端的 Cookie。

  • Cache-Control :控制緩存的行為,如 no-cache、max-age 等。

  • Content-Disposition :指定響應的內容該如何展示(如檔的下載)。

  • 在處理 fetch 返回的 Response 物件時,可以透過呼叫 response.headers.get('Header-Name') 方法來獲取特定的響應頭欄位的值。

    fetch(url)
    .then(response =>{
    const contentType = response.headers.get('Content-Type');
    // 其他處理邏輯
    })
    .catch(error =>{
    // 處理錯誤
    });

    Summer

    錯誤處理

    除了可以使用 catch() 來處理錯誤之外,與使用其他異步操作一樣,我們也可以使用 async/await 來處理異步請求,使程式碼更加簡潔和易讀:

    asyncfunctionfetchData(){
    try{
    const response =awaitfetch('https://api.example.com/data');
    if(response.ok){
    const data =await response.json();
    console.log(data);// 處理解析後的數據
    }else{
    thrownewError('請求失敗');
    }
    }catch(error){
    console.log(error);// 處理錯誤
    }
    }
    fetchData();

    Summer

    取消請求

    在標準的 Fetch API 中,沒有提供直接取消 Fetch 請求的內建方法。但是,可以使用以下方法來模擬或實作取消 Fetch 請求的效果。

    使用 AbortController AbortSignal :這是一種較新的瀏覽器特性,用於生成可以取消請求的訊號。可以建立一個 AbortController 物件,然後將其關聯到 Fetch 請求中,當需要取消請求時,呼叫 AbortController abort() 方法:

    // 建立 AbortController 和關聯的 signal
    const abortController =newAbortController();
    const signal = abortController.signal;
    // 發起 Fetch 請求,並將 signal 傳遞給 fetch 函式
    fetch(url,{ signal })
    .then(response =>{
    // 處理響應
    })
    .catch(error =>{
    if(error.name ==='AbortError'){
    // 請求已被取消
    }else{
    // 處理其他錯誤
    }
    });
    // 當需要取消請求時,呼叫 abort() 方法
    abortController.abort();

    Summer

    瀏覽器相容

    目前,主流瀏覽器都支持 Fetch API:

    # ON

    5

    Axios

    Summer IS HERE

    Axios 是一個基於 Promise 網路請求庫,用於在瀏覽器和 Node.js 中進行 HTTP 請求。在伺服端它使用原生 node.js http 模組, 而在客戶端 (瀏覽端) 則使用 XMLHttpRequests 。Axios 是目前最流行的 HTTP 請求庫,其 npm 每周下載量達到了 4500w+。

    Axios 庫具有以下特點:

  • 瀏覽器和 Node.js :Axios 可在瀏覽器和 Node.js 環境中使用,可以在不同的平台上執行 HTTP 請求。

  • Promise API :Axios 使用 Promise API 進行異步操作,能夠更輕松地處理異步請求和響應。

  • 請求攔截和響應攔截 :可以透過攔截器,在請求發送之前或響應返回之後對請求進行全域性或個人化的變換和處理。可以在請求或響應的不同階段添加公共的請求頭、驗證身份、處理錯誤等。

  • 取消請求 :Axios 允許取消未完成的請求,以避免無效的請求,並減輕伺服器的負擔。取消請求可以透過建立取消令牌、使用取消令牌進行請求配置或者在攔截器中中斷請求來實作。

  • 並行請求 :Axios 提供了執行多個並行請求的能力,可以同時發起多個請求,並在所有請求完成後進行處理。

  • 自動轉換數據 :Axios 可以自動將請求和響應的數據進行格式轉換,包括 JSON、URL 編碼等。無需手動處理數據轉換的過程。

  • 錯誤處理機制 :當請求過程中出現錯誤時,Axios 會返回詳細的錯誤資訊,包括 HTTP 錯誤狀態碼、錯誤描述等。可以根據需要對這些錯誤進行處理和顯示。

  • 簡潔的 API :Axios 的 API 設計簡潔易用,具有直觀的方法命名和參數配置。可以輕松地使用 Axios 進行 GET、POST、PUT、DELETE 等常見的 HTTP 請求。

  • 可以透過以下命令來安裝 Axios:

    // 使用 npm 安裝
    npm install axios
    // 使用 yarn 安裝
    yarn add axios

    下面來進行一個簡單的 get 請求:

    axios.get('https://api.example.com/data')
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理錯誤
    console.error(error);
    });

    這裏使用 axios.get 方法發起了一個 GET 請求,並將請求的 URL 作為參數傳遞給該方法。然後使用 Promise 的 .then 方法處理成功響應,並透過 response.data 獲取響應數據。如果請求失敗,可以透過 Promise 的 .catch 方法捕獲錯誤。

    Summer

    請求方法

    axios 支持透過簡寫方式來執行不同型別的請求:

  • axios.request(config)

  • axios.get(url[, config])

  • axios.delete(url[, config])

  • axios.head(url[, config])

  • axios.options(url[, config])

  • axios.post(url[, data[, config]])

  • axios.put(url[, data[, config]])

  • axios.patch(url[, data[, config]])

  • 對於這些方法,第一個參數是請求的 URL,config 和 data 分別是請求的配置項和請求參數,這兩個參數都是可選的。例如,下面是一個 post 請求:

    const options ={
    headers:{'X-Custom-Header':'value'}
    };
    axios.post('/save',{ a: 10 }, options)
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理錯誤
    console.error(error);
    });

    當作為第二個參數傳遞給 axios.post 函式時,Axios 會自動將 JavaScript 物件序列化為 JSON。 這樣就無需將 POST 正文序列化為 JSON。Axios 還會自動將 Content-Type 請求頭設定為 application/json

    Summer

    多個請求

    在 Axios 中,可以使用 axios.all axios.spread 來處理多個並行的請求:

    const axios =require('axios');
    // 建立多個請求
    const request1 = axios.get('https://api.example.com/data1');
    const request2 = axios.get('https://api.example.com/data2');
    // 並行發送多個請求
    axios.all([request1, request2])
    .then(axios.spread((response1, response2)=>{
    // 處理各個請求的響應
    console.log(response1.data);
    console.log(response2.data);
    }))
    .catch(error =>{
    // 處理錯誤
    console.error(error);
    });

    可以看到,在 .then 方法中使用了 axios.spread 函式將多個請求的響應結果進行解構,透過多個參數分別接收各個請求的響應。可以根據實際情況命名這些參數,並透過 response1.data 、r esponse2.data 等方式獲取各個請求的響應數據。

    Summer

    請求攔截、響應攔截

    在 Axios 中,可以使用 transformRequest 方法在請求發送之前對請求數據進行轉換和處理,它是一個請求攔截器,是一個可選的函式。

    tran sformRequest 函式接收兩個參數: requestData requestHeaders 。其中, requestData 是要發送的請求數據, requestHeaders 是要發送的請求頭資訊。可以在 transformRequest 函式內部對這些參數進行修改,並將修改後的值返回。返回的結果將作為實際發送請求的數據。

    axios({
    url:'https://api.example.com/data',
    method:'post',
    data:{
    id: 12345,
    name:'John Doe'
    },
    transformRequest:(data, headers)=>{
    // 對請求數據進行轉換和處理
    const modifiedData ={...data };// 復制原始數據
    // 修改數據或添加額外欄位
    modifiedData.extraField ='Extra Value';
    // 修改請求頭資訊
    headers['Content-Type']='application/json';
    returnJSON.stringify(modifiedData);// 返回處理後的數據
    }
    })
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理錯誤
    console.error(error);
    });

    這裏使用 Axios 發起了一個 POST 請求。透過傳遞包含 transformRequest 函式的配置物件來定義請求。在 transformRequest 函式內部,復制了原始的請求數據 data ,並進行了一些修改和處理,如添加了額外的欄位和修改了請求頭資訊。最終,將修改後的數據以 JSON 字串的形式返回。Axios 將使用 transformRequest 函式返回的結果作為實際發送請求的數據。

    除了可以對請求進行攔截之外,Axios 還支持對響應進行攔截,對響應數據進行轉換和處理。可以透過 transformResponse 響應攔截器來實作。該函式接收一個參數: responseData ,它是從伺服器接收到的原始響應數據。可以在 transformResponse 函式內部對這個參數進行修改,並將修改後的值返回。返回的結果將作為實際處理響應的數據。

    axios.get('https://api.example.com/data',{
    transformResponse:(data)=>{
    // 對響應數據進行轉換和處理
    const parsedData =JSON.parse(data);// 解析 JSON 字串
    // 修改數據或添加額外欄位
    parsedData.extraField ='Extra Value';
    return parsedData;// 返回處理後的數據
    }
    })
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理錯誤
    console.error(error);
    });

    這裏使用 Axios 發起了一個 GET 請求,並透過傳遞包含 transformResponse 函式的配置物件來定義請求。在 transformResponse 函式內部,對從伺服器接收到的響應數據 data 進行了一些修改和處理,如解析 JSON 字串,添加了額外的欄位。最終將修改後的數據返回。

    Summer

    攔截請求和響應

    Axios 中,可以使用攔截器來攔截請求和響應,並在其被發送或接收之前進行一些額外的處理,可以透過 axios.interceptors 物件來添加攔截器。

    // 添加請求攔截器
    axios.interceptors.request.use(config =>{
    // 在發送請求之前做一些處理
    console.log('請求攔截器');
    // 修改請求配置
    config.headers['Authorization']='Bearer token';
    return config;
    }, error =>{
    // 處理請求錯誤
    console.error('請求出錯:', error);
    });
    // 添加響應攔截器
    axios.interceptors.response.use(response =>{
    // 在接收到響應數據之前做一些處理
    console.log('響應攔截器');
    // 修改響應數據
    response.data ={...response.data, extraField:'Extra Value'};
    return response;
    }, error =>{
    // 處理響應錯誤
    console.error('響應出錯:', error);
    });
    // 發送請求
    axios.get('https://api.example.com/data')
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理請求或響應錯誤
    console.error(error);
    });

    這裏首先使用 axios.interceptors.request.use 方法添加了一個請求攔截器。該攔截器在發送請求之前被呼叫,並接收請求配置物件 config 作為參數。可以對請求配置進行修改,如添加請求頭資訊。最後,要確保返回修改後的配置物件。

    接下來,使用 axios.interceptors.response.use 方法添加了一個響應攔截器。該攔截器在接收到響應數據之前被呼叫,並接收響應物件 response 作為參數。可以對響應數據進行修改,如添加額外的欄位。同樣,要確保返回修改後的響應物件。

    Summer

    客戶端支持 XSRF 防護

    跨站請求偽造(簡稱 XSRF)是一種攻擊 Web 套用的方法,其中攻擊者將自己偽裝成合法且受信任的使用者,以影響應用程式與使用者瀏覽器之間的互動。 有很多方法可以執行此類攻擊,包括 XMLHttpRequest

    幸運的是,Axios 透過允許在發出請求時嵌入額外的身份驗證數據來防止 XSRF。 這使得伺服器能夠發現來自未經授權的位置的請求。以下是使用 Axios 完成此操作的方法:

    const options ={
    method:'post',
    url:'/login',
    xsrfCookieName:'XSRF-TOKEN',
    xsrfHeaderName:'X-XSRF-TOKEN',
    };
    axios(options)
    .then(response =>{
    // 處理成功響應
    console.log(response.data);
    })
    .catch(error =>{
    // 處理請求錯誤
    console.error(error);
    });

    這裏有兩個 xsrf 相關的內容:

  • xsrfCookieName: 'XSRF-TOKEN' :用於跨站請求偽造(XSRF/CSRF)保護的配置選項之一。它指定了儲存 XSRF 令牌的 cookie 的名稱。XSRF 令牌用於防止惡意網站發起對已驗證使用者的請求。

  • xsrfHeaderName: 'X-XSRF-TOKEN' :用於跨站請求偽造(XSRF/CSRF)保護的配置選項之一。它指定了包含 XSRF 令牌的請求頭的名稱。伺服器端可以透過檢查該請求頭來驗證請求的合法性。

  • Summer

    請求進度

    Axios 的另一個有趣的功能是能夠監控請求的進度,這在下載或上傳大檔時特別有用,可以使用 onUploadProgress onDownloadProgress 兩個配置選項來實作。

    對於上傳進度,可以使用 onUploadProgress 配置選項。它會在上傳數據時觸發,並提供關於上傳進度的資訊。

    axios.post('/upload', data,{
    onUploadProgress: progressEvent =>{
    const percentCompleted =Math.round((progressEvent.loaded * 100)/ progressEvent.total);
    console.log(`上傳進度:${percentCompleted}%`);
    },
    })
    .then(response =>{
    console.log(response.data);
    })
    .catch(error =>{
    console.error(error);
    });

    這裏發送了一個 POST 請求,在配置選項中使用了 onUploadProgress 。當數據上傳過程中觸發進度事件時,回呼函式會被執行。在回呼函式中,我們計算出了已上傳數據的百分比,並將其打印出來。

    對於下載進度,可以使用 onDownloadProgress 配置選項。它會在接收到響應數據時觸發,並提供關於下載進度的資訊。

    axios.get('/download',{
    onDownloadProgress: progressEvent =>{
    const percentCompleted =Math.round((progressEvent.loaded * 100)/ progressEvent.total);
    console.log(`下載進度:${percentCompleted}%`);
    },
    })
    .then(response =>{
    console.log(response.data);
    })
    .catch(error =>{
    console.error(error);
    });

    這裏發送了一個 GET 請求,在配置選項中使用了 onDownloadProgress 。當數據下載過程中觸發進度事件時,回呼函式會被執行。在回呼函式中,我們計算出了已下載數據的百分比,並將其打印出來。

    Summer

    取消請求

    在 Axios 中,可以使用取消令牌(cancel token)來取消請求。取消令牌是一個物件,它表示一個具體的取消操作,並允許在需要時中止請求。

    // 建立一個取消令牌源
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    // 發送請求
    axios.get('/api/data',{
    cancelToken: source.token
    })
    .then(response =>{
    console.log(response.data);
    })
    .catch(error =>{
    if(axios.isCancel(error)){
    console.log('請求已被取消:', error.message);
    }else{
    console.error(error);
    }
    });
    // 取消請求
    source.cancel('取消請求的原因');

    這裏,先建立了一個取消令牌源 source 。然後,發送 GET 請求時將 cancelToken 配置選項設定為 source.token ,即將取消令牌與該請求關聯起來。當需要取消請求時,呼叫 source.cancel() 方法,並傳入取消請求的原因作為參數。

    在請求的 .catch() 方法中,我們使用 axios.isCancel(error) 來判斷捕獲的錯誤是否是一個已取消的請求。如果是取消請求導致的錯誤,則會打印出 '請求已被取消' 的提示資訊。否則,將打印出其他型別的錯誤。

    Summer

    請求超時

    可以使用 timeout 配置選項設定 Axios 請求的超時時間,這個選項指定了請求在多少毫秒後如果沒有得到響應就會超時。

    axios.get('/api/data',{
    timeout: 5000 // 設定超時時間為5秒
    })
    .then(response =>{
    console.log(response.data);
    })
    .catch(error =>{
    console.error(error);
    });

    發送了一個 GET 請求,並在配置選項中設定了 timeout 為 5000 毫秒(即 5 秒)。如果請求在 5 秒內沒有得到響應,就會觸發超時錯誤。在超時錯誤的情況下,請求會被自動取消,並且進入 .catch() 分支。您可以根據需要進行錯誤處理。

    註意,如果不設定 timeout 選項,預設情況下 Axios 請求是沒有超時限制的。

    6

    小結

    Summer IS HERE

    相對於 Fetch、XMLHttpRequest 和 Ajax,我還是更喜歡 Axios。它提供了簡潔易用的 API,統一的錯誤處理和攔截器支持,取消請求和超時處理功能,以及基於 Promise 的鏈式呼叫和跨瀏覽器相容性。這些特性使得使用 Axios 更方便、高效,並提供更好的開發體驗。