美文网首页
Axios、Fetch、Ajax的实现区别及与XMLHttpRe

Axios、Fetch、Ajax的实现区别及与XMLHttpRe

作者: 沉默紀哖呮肯伱酔 | 来源:发表于2021-07-28 15:03 被阅读0次
    // 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的实现区别及与XMLHttpRe

          本文链接:https://www.haomeiwen.com/subject/extamltx.html