淺談 Fetch

Fetch

參考: developers.google.com/web/updates…javascript

如今可能還有一些很舊的程序還在使用XHR,相似下面的寫法:java

const request = new XMLHttpRequest()
request.responseType = 'json'
request.open('GET', '/url', true)
request.onload = () => {
  console.log(request.response)
}
request.onerror = () => {
  console.log('shits happen!')
}
request.send(null)
複製代碼

這樣子使用XHR進行異步訪問、讀取資源顯得很繁瑣,相對比Fetch()容許你建立相似XHR的network訪問,可是使用更簡單並且乾淨的API,不須要屢次回調而且記住XHR複雜的API。Fetch API底層是經過Promises實現。web

XMLHttpRequest

一個相對完整的XMLHttpRequest至少須要監聽兩個事件(onload、onerror)來實現成功和失敗的回調,以及調用open()和send()json

function reqListener() {
  var data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError(err) {
  console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();
複製代碼

Fetch

一個簡單的Fetch例子以下:api

fetch('./api/some.json')
  .then(
    function(response) {
      if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
          response.status);
        return;
      }

      // Examine the text in the response
      response.json().then(function(data) {
        console.log(data);
      });
    }
  )
  .catch(function(err) {
    console.log('Fetch Error :-S', err);
  });
複製代碼

Fetch的語法更加語義化、比較好理解。在上面的例子裏咱們先判斷response的status碼,若是是200咱們纔將response解析爲JSON安全

fetch()請求返回的response是Stream對象,所以咱們調用response.json時因爲異步讀取流對象因此返回的是一個Promise對象。cookie

Fetch用async優化代碼

因爲Fetch底層是用Promise實現,咱們能夠直接用async來優化上面的代碼,減小回調,使其更加語義化、容易理解app

async function geturl(){
	try{
		let res = await fetch('./api/some.json')
		if(res.status == 200){
			console.log(await res.text())
		}
	} catch(err){
		console.log(err)
	}
}
複製代碼

Response元數據

在上面的例子裏,咱們瞭解了Response對象的status狀態以及怎麼把response對象轉換爲JSON對象,讓咱們來看看Response對象的其餘元數據:cors

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});
複製代碼

Response類型

當咱們發起一個Fetch請求時,返回的response響應會自帶一個response.type屬性(basic、cors、opaque)。response.type屬性說明了異步資源的來源,同時還有相應的處理方式。異步

當咱們發起一個同源請求時,response.type爲basic,並且你能夠從response讀取所有信息。

若是咱們訪問一個非同源域名,而且有返回相應的CORs響應頭時,那麼該請求類型是cors。cors和basic很類似,就除了cors響應裏你沒法訪問Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

當咱們對一個不一樣源的域名發起請求時,若是返回的響應頭部沒有CORS信息,那麼這個response對應的類型就是opaque類型。一個opaque響應是沒法讀取返回的數據、狀態,甚至沒法肯定這個請求是否成功。

咱們能夠自定義Fetch請求的模式,要求返回對應類型的響應,有如下幾種響應:

  1. same-origin 只返回同源請求,其餘類型會被reject
  2. cors 接收同源、非同源請求,返回有CORs頭部的響應
  3. cors-with-forced-preflight 在發出請求前會先作一次安全性檢查
  4. no-cors 用來發起沒有CORS頭部而且非同源請求,而且會返回opaque響應。可是目前這種類型只能在Service Worker裏使用,在window.fetch裏不能用
fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(function(response) {
    return response.text();
  })
  .then(function(text) {
    console.log('Request successful', text);
  })
  .catch(function(error) {
    log('Request failed', error)
  });
複製代碼

承諾鏈

由於Fetch返回的response是基於Promise實現,因此咱們能夠像鏈條同樣把幾個Promise串接起來,以下所示:

function status(response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json(response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(function(data) {
    console.log('Request succeeded with JSON response', data);
  }).catch(function(error) {
    console.log('Request failed', error);
  });
複製代碼

固然了,咱們也能夠用async進行代碼優化

async function geturl(url){
	try {
		let res = await fetch(url)
		if(res.status >= 200 && res.status < 300){
			console.log('Request succeeded with JSON response', await res.json())
		}
	}catch (err){
		console.log(err)
	}
}

geturl('users.json')
複製代碼

Post請求

當咱們使用Fetch發起Post請求時,須要手動設置method參數和body參數,以下:

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(function (data) {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function (error) {
    console.log('Request failed', error);
  });
複製代碼

若是沒有顯式指定method參數,那麼默認Get請求

帶Cookie發送請求

若是咱們想要在異步請求中帶上cookie參數,那麼須要顯式指定credentials參數:

fetch(url, {
  credentials: 'include'
})
複製代碼
相關文章
相關標籤/搜索