Axios、Fetch、Ajax的實現(xiàn)區(qū)別及與XMLHttpRequest之間的關(guān)系

// todo CSRF攻擊/XSS攻擊

1、Ajax

AJAX即“Asynchronous JavaScript and XML”(異步的JavaScript與XML技術(shù))

  • XMLHttpRequest api是Ajax的核心
  • 什么是 XMLHttpRequest 對象?
    XMLHttpRequest 對象用于在后臺與服務(wù)器交換數(shù)據(jù)。所有現(xiàn)代的瀏覽器都支持 XMLHttpRequest 對象。
const xhr = new XMLHttpRequest();
// open(method, url, async, username, password)
// username 和 password 參數(shù)是可選的,為 url 所需的授權(quán)提供認證資格。如果指定了,它們會覆蓋 url 自己指定的任何資格。

xhr.open('GET', '/your-url', true);
xhr.send();

2、Axios

Axios基于Promise用于瀏覽器和Node.js的http客戶端。
Axios的特性如下:

  • 在瀏覽器中創(chuàng)建 XMLHttpRequests
  • Make http requests from node.js
  • 支持Promise API
  • 攔截請求和響應(yīng)
  • 轉(zhuǎn)換請求和響應(yīng)數(shù)據(jù)
  • 取消請求
  • JSON 數(shù)據(jù)的自動轉(zhuǎn)換
  • 客戶端支持防止XSRF
  • Axios的核心還是使用XHR來進行通信

3、Fetch

image.png

Fetch 是一種新的原生 JavaScript API,目前大多數(shù)瀏覽器都支持。Fetch 允許您發(fā)出類似于 XMLHttpRequest。與 XMLHttpRequest 相比,它是對XMLHttpRequest API 的改進。Fetch 和 XMLHttpRequest 之間的主要區(qū)別在于 Fetch API 使用 Promise,因此避免了回調(diào)地獄。

Fetch特征如下:

  • Fetch是基于Promise設(shè)計的。
  • 不支持使用XHR,如果瀏覽器不支持Fetch則需要使用 XHR 實現(xiàn)。
  • Fetch只對網(wǎng)絡(luò)請求報錯,對400,500都當做成功的請求,需要封裝去處理。
  • Fetch 請求默認是不帶 cookie 的,需要設(shè)置 fetch(url, {credentials: 'include'})。
  • Fetch不支持abort,因為Fetch返回的是一個promise,不支持超時控制,使用setTimeout及Promise.reject的實現(xiàn)的超時控制并不能阻止請求過程繼續(xù)在后臺運行,造成了量的浪費。
  • 當前IE9, Firefox, Chrome基本已經(jīng)內(nèi)置Fetch的全局方法。
  • 如果不支持則用 XHR 實現(xiàn),只要引入一個 polyfill 就可以了, github/fetch的源碼實現(xiàn)。
  • https://github.com/github/fetch/blob/master/fetch.js
// 摘抄代碼片段
export function fetch(input, init) {
  return new Promise(function(resolve, reject) {
    var request = new Request(input, init)

    if (request.signal && request.signal.aborted) {
      return reject(new DOMException('Aborted', 'AbortError'))
    }

    var xhr = new XMLHttpRequest()

    function abortXhr() {
      xhr.abort()
    }

    xhr.onload = function() {
      var options = {
        status: xhr.status,
        statusText: xhr.statusText,
        headers: parseHeaders(xhr.getAllResponseHeaders() || '')
      }
      options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
      var body = 'response' in xhr ? xhr.response : xhr.responseText
      setTimeout(function() {
        resolve(new Response(body, options))
      }, 0)
    }

    xhr.onerror = function() {
      setTimeout(function() {
        reject(new TypeError('Network request failed'))
      }, 0)
    }

    xhr.ontimeout = function() {
      setTimeout(function() {
        reject(new TypeError('Network request failed'))
      }, 0)
    }

    xhr.onabort = function() {
      setTimeout(function() {
        reject(new DOMException('Aborted', 'AbortError'))
      }, 0)
    }

    function fixUrl(url) {
      try {
        return url === '' && global.location.href ? global.location.href : url
      } catch (e) {
        return url
      }
    }

    xhr.open(request.method, fixUrl(request.url), true)

    if (request.credentials === 'include') {
      xhr.withCredentials = true
    } else if (request.credentials === 'omit') {
      xhr.withCredentials = false
    }

    if ('responseType' in xhr) {
      if (support.blob) {
        xhr.responseType = 'blob'
      } else if (
        support.arrayBuffer &&
        request.headers.get('Content-Type') &&
        request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1
      ) {
        xhr.responseType = 'arraybuffer'
      }
    }

    if (init && typeof init.headers === 'object' && !(init.headers instanceof Headers)) {
      Object.getOwnPropertyNames(init.headers).forEach(function(name) {
        xhr.setRequestHeader(name, normalizeValue(init.headers[name]))
      })
    } else {
      request.headers.forEach(function(value, name) {
        xhr.setRequestHeader(name, value)
      })
    }

    if (request.signal) {
      request.signal.addEventListener('abort', abortXhr)

      xhr.onreadystatechange = function() {
        // DONE (success or failure)
        if (xhr.readyState === 4) {
          request.signal.removeEventListener('abort', abortXhr)
        }
      }
    }

    xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
  })
}

fetch.polyfill = true

if (!global.fetch) {
  global.fetch = fetch
  global.Headers = Headers
  global.Request = Request
  global.Response = Response
}

fetch的Requset對象等同于 XMLHttpRequest.send()
所以并不能確定Fetch底層使用的技術(shù)是什么,因為是瀏覽器廠商做的原生支持。

4、umi-request

umi-request是一個網(wǎng)絡(luò)請求庫,基于 Fetch 封裝, 旨在為開發(fā)者提供一個統(tǒng)一的api調(diào)用方式, 簡化使用, 并提供諸如緩存, 超時, 字符編碼處理, 錯誤處理等常用功能。
支持的功能如下:

  • url 參數(shù)自動序列化
  • post 數(shù)據(jù)提交方式簡化
  • response 返回處理簡化
  • api 超時支持
  • api 請求緩存支持
  • 支持處理 gbk
  • 類 axios 的 request 和 response 攔截器(interceptors)支持
  • 統(tǒng)一的錯誤處理方式

5、wx-request

不支持Promise方式調(diào)用

wx.request({
  url: 'your-url', 
  data: {
    a: '',
  },
  header: {
    'content-type': 'application/json' 
  },
  success (res) {
    console.log(res.data)
  }
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容