fetch簡明學習

小火柴的藍色理想發表於2018-04-11

前面的話

  Fetch API 提供了一個 JavaScript介面,用於訪問和操縱HTTP管道的部分,例如請求和響應。它還提供了一個全域性 fetch()方法,該方法提供了一種簡單,合乎邏輯的方式來跨網路非同步獲取資源。本文將詳細介紹fetch的相關內容

 

概述

  跨網路非同步獲取資源的功能以前是使用 XMLHttpRequest實現的。Fetch提供了一個更好的替代方法,可以很容易地被其他技術使用,例如 Service Workers。Fetch還提供了單個邏輯位置來定義其他HTTP相關概念,例如 CORS和HTTP的擴充套件

  fetch 規範與 jQuery.ajax() 主要有兩種方式的不同

  1、當接收到一個代表錯誤的 HTTP 狀態碼時,從 fetch()返回的 Promise 不會被標記為 reject, 即使該 HTTP 響應的狀態碼是 404 或 500。相反,它會將 Promise 狀態標記為 resolve (但是會將 resolve 的返回值的 ok 屬性設定為 false ), 僅當網路故障時或請求被阻止時,才會標記為 reject

  2、預設情況下, fetch 不會從服務端傳送或接收任何 cookies,如果站點依賴於使用者 session,則會導致未經認證的請求(要傳送 cookies,必須設定 credentials 選項)

 

fetch請求

  一個基本的 fetch請求設定起來很簡單。這裡我們通過網路獲取一個影象並將其插入到一個 <img> 元素中。最簡單的用法是隻提供一個引數用來指明想fetch到的資源路徑,然後返回一個包含響應結果的promise(一個 Response 物件)

let myImage = document.querySelector('img');

fetch('flowers.jpg')
.then(function(response) {
    return response.blob();
})
.then(function(myBlob) {
    let objectURL = URL.createObjectURL(myBlob);
    myImage.src = objectURL;
});

 

自定義引數

  fetch() 接受第二個可選引數,一個可以控制不同配置的 init 物件:

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

fetch('flowers.jpg',myInit)
.then(function(response) {
  return response.blob();
})
.then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

 

post

// 通過fetch獲取百度的錯誤提示頁面
fetch('https://www.baidu.com/search/error.html', {
    method: 'POST',
    body: JSON.stringify({a:1}),
   headers: { ...new Headers(headers), 'Content-Type': 'application/json' }
  })
  .then((res)=>{
    return res.text()
  })
  .then((res)=>{
    console.log(res)
  })

 

JSON資料

// 通過fetch獲取百度的錯誤提示頁面
fetch('https://www.baidu.com/rec?platform=wise&ms=1&rset=rcmd&word=123&qid=11327900426705455986&rq=123&from=844b&baiduid=A1D0B88941B30028C375C79CE5AC2E5E%3AFG%3D1&tn=&clientWidth=375&t=1506826017369&r=8255', { // 在URL中寫上傳遞的引數
    method: 'GET',
    headers: new Headers({
      'Accept': 'application/json' // 通過頭指定,獲取的資料型別是JSON
    })
  })
  .then((res)=>{
    return res.json() // 返回一個Promise,可以解析成JSON
  })
  .then((res)=>{
    console.log(res) // 獲取JSON資料
  })

 

檢測成功

  如果遇到網路故障,fetch() promise 將會 reject,帶上一個 TypeError 物件。雖然這個情況經常是遇到了許可權問題或類似問題——比如 404 不是一個網路故障。想要精確的判斷 fetch() 是否成功,需要包含 promise resolved 的情況,此時再判斷 Response.ok 是不是為 true

fetch('flowers.jpg').then(function(response) {
  if(response.ok) {
    response.blob().then(function(myBlob) {
      var objectURL = URL.createObjectURL(myBlob);
      myImage.src = objectURL;
    });
  } else {
    console.log('Network response was not ok.');
  }
})
.catch(function(error) {
  console.log('There has been a problem with your fetch operation: ' + error.message);
});

 

Headers

  使用 Headers 的介面,可以通過 Headers() 建構函式來建立一個自己的 headers 物件。一個 headers 物件是一個簡單的多名值對:

var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");

  也可以傳一個多維陣列或者物件字面量:

myHeaders = new Headers({
  "Content-Type": "text/plain",
  "Content-Length": content.length.toString(),
  "X-Custom-Header": "ProcessThisImmediately",
});

  它的內容可以被獲取:

console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
 
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.getAll("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
 
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.getAll("X-Custom-Header")); // [ ]

 

封裝

  下面是筆者在react中對fetch的精簡版封裝

import { showLoading, hideLoading, showAlertText, hideAlertText } from '@/components/Alert/module'
import { logout } from '@/components/Auth/module'

const async = ({ dispatch, url, method, data, headers, success, fail, doHideAlert }) => {
  // 顯示loading
  dispatch(showLoading())
  let fetchObj = {}
  if (method) {
    fetchObj = {
      method,
      body: JSON.stringify(data),
      headers: new Headers({ ...headers, 'Content-Type': 'application/json' })
    }
  }
  fetch(url, fetchObj).then(res => {
    // 關閉loading
    dispatch(hideLoading())
    return res.json()
  }).then(json => {
    // 成功
    if (json.code === 0) {
      !doHideAlert && dispatch(showAlertText(json.message))
      setTimeout(() => {
        dispatch(hideAlertText())
      }, 1000)
      success && success(json.result)
      // 自定義錯誤
    } else if (json.code === 1) {
      dispatch(showAlertText(json.message))
      // 系統錯誤
    } else if (json.code === 2) {
      dispatch(showAlertText(json.message))
      fail && fail(json.err)
      // 認證失敗
    } else if (json.code === 3) {
      dispatch(showAlertText(json.message))
      dispatch(logout)
    }
  }).catch(() => {
    dispatch(showAlertText('伺服器故障'))
  })
}

export default async

 

相關文章