Axios、Fetch、Ajax的实现区别及与XMLHttpRequest之间的关系

// todo CSRF攻击/XSS攻击

1、Ajax

AJAX即“Asynchronous JavaScript and XML”(异步的JavaScript与XML技术)

  • XMLHttpRequest api是Ajax的核心
  • 什么是 XMLHttpRequest 对象?
    XMLHttpRequest 对象用于在后台与服务器交换数据。所有现代的浏览器都支持 XMLHttpRequest 对象。
const xhr = new XMLHttpRequest();
// open(method, url, async, username, password)
// username 和 password 参数是可选的,为 url 所需的授权提供认证资格。如果指定了,它们会覆盖 url 自己指定的任何资格。

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

2、Axios

Axios基于Promise用于浏览器和Node.js的http客户端。
Axios的特性如下:

  • 在浏览器中创建 XMLHttpRequests
  • Make http requests from node.js
  • 支持Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • JSON 数据的自动转换
  • 客户端支持防止XSRF
  • Axios的核心还是使用XHR来进行通信

3、Fetch

image.png

Fetch 是一种新的原生 JavaScript API,目前大多数浏览器都支持。Fetch 允许您发出类似于 XMLHttpRequest。与 XMLHttpRequest 相比,它是对XMLHttpRequest API 的改进。Fetch 和 XMLHttpRequest 之间的主要区别在于 Fetch API 使用 Promise,因此避免了回调地狱。

Fetch特征如下:

  • Fetch是基于Promise设计的。
  • 不支持使用XHR,如果浏览器不支持Fetch则需要使用 XHR 实现。
  • Fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理。
  • Fetch 请求默认是不带 cookie 的,需要设置 fetch(url, {credentials: 'include'})。
  • Fetch不支持abort,因为Fetch返回的是一个promise,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费。
  • 当前IE9, Firefox, Chrome基本已经内置Fetch的全局方法。
  • 如果不支持则用 XHR 实现,只要引入一个 polyfill 就可以了, github/fetch的源码实现。
  • 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底层使用的技术是什么,因为是浏览器厂商做的原生支持。

4、umi-request

umi-request是一个网络请求库,基于 Fetch 封装, 旨在为开发者提供一个统一的api调用方式, 简化使用, 并提供诸如缓存, 超时, 字符编码处理, 错误处理等常用功能。
支持的功能如下:

  • url 参数自动序列化
  • post 数据提交方式简化
  • response 返回处理简化
  • api 超时支持
  • api 请求缓存支持
  • 支持处理 gbk
  • 类 axios 的 request 和 response 拦截器(interceptors)支持
  • 统一的错误处理方式

5、wx-request

不支持Promise方式调用

wx.request({
  url: 'your-url', 
  data: {
    a: '',
  },
  header: {
    'content-type': 'application/json' 
  },
  success (res) {
    console.log(res.data)
  }
})

你可能感兴趣的:(Axios、Fetch、Ajax的实现区别及与XMLHttpRequest之间的关系)