使用 Fetch完成AJAX請求


使用 Fetch完成AJAX請求

寫在前面

無論用JavaScript發送或獲取信息,我們都會用到Ajax。Ajax不需要刷新頁面就能發送和獲取信息,能使網頁實現異步更新。

幾年前,初始化Ajax一般使用jQuery的ajax方法:

$.ajax('some-url', {
  success: (data) => { /* do something with the data */ },
  error: (err) => { /* do something when an error happens */}
});

也可以不用jQuery,但不得不使用XMLHttpRequest,然而這是[相當復雜]

幸虧,瀏覽器現在支持Fetch API,可以無須其他庫就能實現Ajax

瀏覽器支持

fetch是相對較新的技術,當然就會存在瀏覽器兼容性的問題,當前各個瀏覽器低版本的情況下都是不被支持的,因此為了在所有主流瀏覽器中使用fetch 需要考慮 fetch 的 polyfill 了

require('es6-promise').polyfill();
require('isomorphic-fetch');

引入這兩個文件,就可以支持主流瀏覽器了

Fetch獲取數據解讀

使用Fetch獲取數據很容易。只需要Fetch你想獲取資源。

假設我們想通過GitHub獲取一個倉庫,我們可以像下面這樣使用:

fetch('https://api.github.com/users/chriscoyier/repos');

Fetch會返回Promise,所以在獲取資源后,可以使用.then方法做你想做的。

fetch('https://api.github.com/users/chriscoyier/repos')
  .then(response => {/* do something */})

如果這是你第一次遇見Fetch,也許驚訝於Fetch返回的response。如果console.log返回的response,會得到下列信息:

{
  body: ReadableStream
  bodyUsed: false
  headers: Headers
  ok : true
  redirected : false
  status : 200
  statusText : "OK"
  type : "cors"
  url : "http://some-website.com/some-url"
  __proto__ : Response
}

可以看出Fetch返回的響應能告知請求的狀態。從上面例子看出請求是成功的(oktruestatus是200),但是我們想獲取的倉庫名卻不在這里。

顯然,我們從GitHub請求的資源都存儲在body中,作為一種可讀的流。所以需要調用一個恰當方法將可讀流轉換為我們可以使用的數據。

Github返回的響應是JSON格式的,所以調用response.json方法來轉換數據。

還有其他方法來處理不同類型的響應。如果請求一個XML格式文件,則調用response.text。如果請求圖片,使用response.blob方法。

所有這些方法(response.json等等)返回另一個Promise,所以可以調用.then方法處理我們轉換后的數據。

fetch('https://api.github.com/users/chriscoyier/repos')
  .then(response => response.json())
  .then(data => {
    // data就是我們請求的repos
    console.log(data)
  });

可以看出Fetch獲取數據方法簡短並且簡單。

接下來,讓我們看看如何使用Fetch發送數據。

Fetch發送數據解讀

使用Fetch發送也很簡單,只需要配置三個參數。

fetch('some-url', options);

第一個參數是設置請求方法(如postputdel),Fetch會自動設置方法為get

第二個參數是設置頭部。因為一般使用JSON數據格式,所以設置ContentTypeapplication/json

第三個參數是設置包含JSON內容的主體。因為JSON內容是必須的,所以當設置主體時會調用JSON.stringify

實踐中,post請求會像下面這樣:

let content = {some: 'content'};

// The actual fetch request
fetch('some-url', {
  method: 'post',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(content)
})
// .then()...

API

fetch(url, { // url: 請求地址
    method: "GET", // 請求的方法POST/GET等
    headers: { // 請求頭(可以是Headers對象,也可是JSON對象)
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: , // 請求發送的數據 blob、BufferSource、FormData、URLSearchParams(get或head方法中不能包含body)
    cache: 'default', // 是否緩存這個請求
    credentials: 'same-origin', //要不要攜帶 cookie 默認不攜帶 omit、same-origin 或者 include
    mode: "",
    /*  
        mode,給請求定義一個模式確保請求有效
        same-origin:只在請求同域中資源時成功,其他請求將被拒絕(同源策略)
        cors : 允許請求同域及返回CORS響應頭的域中的資源,通常用作跨域請求來從第三方提供的API獲取數據
        cors-with-forced-preflight:在發出實際請求前執行preflight檢查
        no-cors : 目前不起作用(默認)

    */
}).then(resp => {
    /*
        Response 實現了 Body, 可以使用 Body 的 屬性和方法:

        resp.type // 包含Response的類型 (例如, basic, cors).

        resp.url // 包含Response的URL.

        resp.status // 狀態碼

        resp.ok // 表示 Response 的成功還是失敗

        resp.headers // 包含此Response所關聯的 Headers 對象 可以使用

        resp.clone() // 創建一個Response對象的克隆

        resp.arrayBuffer() // 返回一個被解析為 ArrayBuffer 格式的promise對象

        resp.blob() // 返回一個被解析為 Blob 格式的promise對象

        resp.formData() // 返回一個被解析為 FormData 格式的promise對象

        resp.json() // 返回一個被解析為 Json 格式的promise對象

        resp.text() // 返回一個被解析為 Text 格式的promise對象
    */
    if (resp.status === 200) return resp.json();
    // 注: 這里的 resp.json() 返回值不是 js對象,通過 then 后才會得到 js 對象
    throw New Error('false of json');
}).then(json => {
    console.log(json);
}).catch(error => {
    consolr.log(error);
})

常用情況

1.請求 json

fetch('http://xxx/xxx.json').then(res => {
        return res.json();
    }).then(res => {
        console.log(res);
    })

2. 請求文本

fetch('/xxx/page').then(res => {
        return res.text();
    }).then(res => {
        console.log(res);
    })

3. 發送普通json數據

 fetch('/xxx', {
        method: 'post',
        body: JSON.stringify({
            username: '',
            password: ''
        })
    });

4. 發送Form表單數據

var form = document.querySelector('form');
    fetch('/xxx', {
        method: 'post',
        body: new FormData(form)
    });

5. 獲取圖片

 fetch('/xxx').then(res => {
        return res.blob();
    }).then(res => {
        document.querySelector('img').src = URL.createObjectURL(imageBlob);
    })

6. 上傳文件

    var file = document.querySelector('.file')
    var data = new FormData()
    data.append('file', file.files[0])
    fetch('/xxx', {
      method: 'POST',
      body: data
    })

7. 封裝

    require('es6-promise').polyfill();
    require('isomorphic-fetch');

    export default function request(method, url, body) {
        method = method.toUpperCase();
        if (method === 'GET') {
            body = undefined;
        } else {
            body = body && JSON.stringify(body);
        }

        return fetch(url, {
            method,
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            },
            body
        }).then((res) => {
            if (res.status >= 200 && res.status < 300) {
                return res;
            } else {
                return Promise.reject('請求失敗!');
            }
        })
    }

    export const get = path => request('GET', path);
    export const post = (path, body) => request('POST', path, body);
    export const put = (path, body) => request('PUT', path, body);
    export const del = (path, body) => request('DELETE', path, body);

參考

總結

Fetch是很好的方法,能發送和接收數據。不需要在編寫XHR請求或依賴於jQuery。

盡管Fetch很好,但是其錯誤處理不是很直接。在處理之前,需要讓錯誤信息進入到catch方法中。

聽說有個zlFetch庫,改善了Fetch錯誤處理de問題。

But ! 現在有了Axios了,還跟我扯啥犢子呢!直接一步到位用Axios吧小盆友~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM