HTML5 API fetch詳解(如有細節紕漏, 歡迎指正)

Fetch API

回顧一下XMLHttpRequest的問題

  1. 所有的功能全部集中在一個對象上, 容易書寫出混亂而且不容易維護的代碼
  2. 採用傳統的事件驅動模式, 無法適配新的 Promise api

Fetch Api的特點

  1. 並非取代ajax, 而是對ajax傳統api的改進
  2. 精細的功能分割: 頭部信息, 請求信息, 響應信息等均分佈到不同的對象, 更利於處理各種複雜的ajax場景
  3. 使用Promise api, 更利於異步代碼的書寫
  4. fetch屬於web api, 理所當然只能在瀏覽器端運行

Fetch Api的基本使用

參數

該函數有兩個參數:

  1. 必填: 字符串, 對應的是請求地址
//請求數據的函數如下
const getDefaultData = () => {
    //在論壇中我找到了一個請求網易雲音樂別人已經寫好的接口,可以用來測試
    const url = 'https://api.imjad.cn/cloudmusic/?type=song&id=32785674'; 
    fetch(url); 
}

// 假設我們的html頁面中有一個按鈕, 點擊這個按鈕就會開始請求數據,然後我們現在獲取到這個按鈕
const btn = document.querySelector('button');
btn.onclick = () => {
    getDefaultData();
}

當上面的代碼寫好, 我們進行點擊操作時, 服務器相應的給我們返回了數據
在這裏插入圖片描述

請求配置對象(紅色爲比較常用的, 綠色爲目前不太常用的)

  • method: 字符串, 請求方法, 默認值GET
  • headers: 對象, 請求頭信息
  • body: 請求體的內容, 必須匹配請求頭中Content-Type
  • mode:字符串, 請求模式
    • cors: 默認值, 配置爲該值, 會在請求頭中加入origin和referer
    • no-cors: 配置爲該值, 將不會再請求頭中加入origin和referer, 跨域的時候可能會出現問題
    • same-origin: 配置爲該值, 則指示請求必須在同一個域中發生, 如果請求其他域, 則會報錯
  • credentials: 如何攜帶憑據
    • omit: 默認值, 不攜帶cookie
      - same-origin: 請求同源地址時攜帶cookie
      -include: 請求任何地址都要攜帶cookie
  • cache: 配置緩存模式
    • default: 表示fetch請求之前將檢查一下http的緩存
    • no-store: 表示fetch請求將完全忽略http緩存的存在, 這意味着請求之前將不再檢查http的緩存, 拿到響應以後他也不會再更新http緩存
    • no-cache: 如果存在緩存, 那麼fetch將發送一個條件查詢request和一個正常的request, 拿到響應以後, 他會更新http緩存
    • reload: 表示fetch請求之前將忽略http緩存的存在, 但是在請求得到響應以後, 他將主動更新http緩存
    • force-cache: 表示fetch請求不顧一切的依賴緩存, 即使緩存過期了, 他依然從緩存中讀取, 除非沒有任何緩存, 那麼他纔會發送一個正常的request
    • only-if-cached: 表示fetch請求不顧一切的依賴緩存, 即使緩存過期了, 他依然從緩存中讀取, 如果沒有任何緩存, 那麼他將拋出一個錯誤
//配置對象書寫
const getData = function() {
    const url = 'xxx/api';
    const config = {
        method: 'POST',  // 寫請求方法
        headers: {
            // 配置請求頭
            //例如: "Content-Type": 'application/json'
        },
        body: {
            // 配置請求體, 比如POST請求要傳遞的數據
        }
        //...其他不常用配置
    }
    fetch(url, config); // 開始請求數據
}

返回值

fetch函數返回一個Promise對象

  • 當收到服務器的返回結果以後, Promise進入resolved狀態, 狀態數據爲Response對象(服務器不一定要200返回, 只要返回了東西都會走resolved狀態)
const getDefaultData = async () => {
            const url = 'https://api.imjad.cn/cloudmusic/?type=song&id=32785674';
            const config = {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: {

                },
                // mode: 'cors'
            }
            // 既然返回的結果是一個Promise, 那麼我們就可以用await等待服務器響應的結果
            try {
                let promise = await fetch(url);
                console.log(promise);
            }catch(err) {
                console.log(err);
            }
        }
        const btn = document.querySelector('button');
        //當按鈕點擊的時候我們開始數據請求
        btn.onclick = function () {
            getDefaultData();
        }
  • 當網絡發生錯誤(或者其他導致無法完成交互的錯誤), Promise進入rejected狀態, 狀態數據爲錯誤信息

Response對象(服務器響應對象)

  1. ok: boolean, 當響應消息在200-299之間時爲true, 其他爲false
  2. status: number 響應的狀態碼
  3. text(): 用於處理文本格式的ajax響應, 他從響應中獲取文本流, 將其讀完, 然後返回一個被解決爲string對象的Promise
const result = await fetch(url, config);
const respText = await result.text();
  1. blob(): 用於處理二進制的文件格式(比如圖片和電子表格)的ajax響應, 他讀取文件的原始數據, 一旦讀取完整個文件, 就返回一個被解決爲blob對象的Promise
const result = await fetch(url, config);
const respBlob = await result.blob(); 
  1. json(): 用於處理JSON格式的Ajax的響應, 他講json數據流轉化爲一個被解決爲JavaScript對象的Promise
const result = await fetch(url, config);
const respJson = await result.json(); 
  1. redirect(): 用於重定向到另一個url, 他會創建一個新的Promise, 以解決來自重定向的url響應
    響應對象示例
    在這裏插入圖片描述

來聊聊Request對象

除了使用基本的fetch方法, 還可以通過創建一個request對象來完成請求, 實際上fetch的內部也會幫你創建一個內部對象

//request對象的創建方式
new Request(url, config)

當我們遇到要複用某些請求的需求時, 就可以用到request對象

function getRespInfo() {
    const url = 'xxx/api';
    const config = {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
        },
    }
    //...body和其他配置
    const request = new Request(url, config);
}

}
function async getData() {
    // 每次都走一次getRespInfo這個函數, 保證每次創建的都是一個新的request對象
    const result = await fetch(getRespInfo());
    const respText = await result.text();
}

注意點: 儘量保證每次請求都是一個新的request對象

再來說說這個Response對象

大多數時候, Response對象都不需要我們自己來構建, 因爲服務器會幫我們封裝好, 但是在某些特殊時候, 比如後端數據還沒寫好, 在這種情況下,我們可能最先想到的就是mock數據, 但是我們也可以手動構建一個Response, 用來幫我們構建測試環境

// 我們有一個用來獲取省市的函數
async function getProvince() {
    // 手動構建的Response對象
    const resp = new Response(
        `[
            {"id": 1, "name": "beijing"},
            {"id": 2, "name": "shanghai"}
        ]`,
        ok: true,
        status: 200
    )
    const result = await getJSON(resp);
    console.log(result);    
}

async function getJSON(resp) {
    return await resp.json();
}

但是因爲我們大部分時間其實不會這樣進行測試, 所以僅瞭解即可

[擴展] Headers對象

在Request和Response對象內部, 會將傳遞配置中的headers請求頭對象轉化爲Headers對象

同時Headers對象提供一些方法:

  1. has(key): 判斷請求頭中是否存在指定的key
const url = 'xxx/api';
const config = {
    headers: {
        'Content-Type': 'application/json'
    }
}
const resp = new Request(url, config);
console.log(resp.headers.has('Content-Type')); //返回true, 因爲我們請求頭中配置了
  1. get(key): 得到請求頭中對應的key所對應的值
const url = 'xxx/api';
const config = {
    headers: {
        'Content-Type': 'application/json'
    }
}
const resp = new Request(url, config);
console.log(resp.headers.get('Content-Type')); //返回'application/json'
  1. set(key, value): 修改請求頭中對應的鍵值對, 如果是修改未存在的, 則會新建一個鍵值對
// 其餘代碼跟上面兩個方法一樣
resp.headers.set(c, 'helloworld'); //這時候請求頭中會多出一個c 並且值爲'helloworld'
  1. append(key, value): 專門用來往請求頭中添加鍵值對
//其餘代碼跟上面三個方法一樣
resp.headers.append(d, 'its tom'); //網請求頭中添加一個d, 值爲'its tom'

需要注意的是, 如果是對重複的屬性用append,並不會覆蓋之前的屬性而是合併

// 假設headers中有a 值爲1,然後我們調用append
resp.headers.append(a, 3); // 這時候headers中a的值爲1,2 
  1. keys(): 得到所有的請求頭的key所組成的集合(iterator)
const url = 'xxx/api';
const config = {
    headers: {
        'Content-Type': 'application/json',
        'a': 1
    }
}
const resp = new Request(url, config);
console.log(resp.headers.keys()); 
  1. values(): 得到所有的請求頭key對應的值所組成的集合(iterator)
const url = 'xxx/api';
const config = {
    headers: {
        'Content-Type': 'application/json',
        'a': 1
    }
}
const resp = new Request(url, config);
console.log(resp.headers.values()); 
  1. entries(): 得到所有的請求頭鍵值對所組成的集合(iterator)
const url = 'xxx/api';
const config = {
    headers: {
        'Content-Type': 'application/json',
        'a': 1
    }
}
const resp = new Request(url, config);
console.log(resp.headers.entries()); 

基礎內容到此爲止, 關於細節部分如果有問題 希望被指出, 好做更改, Thanks for reading

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章