必知必会的axios学习经(更新中)

简介: 必知必会的axios学习经(更新中)

文章目录

MDN文档

官网

HTTP 相关

**超文本传输协议(HTTP)**是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待直到收到服务器端响应。HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。

HTTP请求交互的基本过程

HTTP 报文

请求报文

  • 请求行

method url

GET /product_detail?id=2

POST /login

  • 多个请求头

Host : www.baidu.com

Cookie: xx

Content-Type: application/x-www-form-urlencoded 或者 application/json

  • 请求体

username=tom&pwd=123

{“username”:“tom”, “pwd”:“123” }

响应报文

  • 响应状态行

status statusText

  • 多个响应头

Contetn-Type: text/html; charset=utf-8

set-cookies:BD_CK_SAM=1; path=/

  • 响应体

html文本、 json文本 …

post 请求体参数格式

  • Conten-Type: application/x-www-form-urlencoded; charset=utf-8

用于键值对参数,参数的键值用=连接,参数之间用&连接

https://search.bilibili.com/all?keyword=axios&from_source=nav_search_new

  • Conten-Type:application/json; charset=utf-8

用于json 字符串参数

  • Conten-Type:multipart/form-data

用于文件上传

常见的响应状态码

200 OK 请求成功。一般用于 GET 与 POST 请求

201 Created 已创建。成功请求并创建了新的资源

401 Unauthorized 未授权/请求要求用户的身份认证

404 Not Found 服务器无法根据客户端的请求找到资源

500 Internal Server Error 服务器内部错误,无法完成请求

不同类型的请求及其作用

  1. GET: 从服务器端读取数据
  2. POST: 向服务器端添加新数据
  3. PUT: 更新服务器端已经数据
  4. DELETE: 删除服务器端数据

API 分类

  • restful api

同一个请求路径可以进行多个操作

GET/POST/PUT/DELETE

  • restless api

请求方式不决定请求的CRUD操作

一个请求路径只有一个操作

一般只有 GET/POST

query

返回一个符合查询的数组

params

返回一个对象

理解XHR

区别一般http请求与ajax请求

  1. ajax 请求是一种特别的 http 请求
  2. 对服务器来说,没有任何区别,但对浏览器来说不一样
  3. 浏览器端发出请求
  • 只有XHRfetch发出的请求才是ajax请求
  1. ajax 引擎

帮我们发送ajax请求的一段内置代码

  1. 浏览器接收到的数据
  • 一般请求:浏览器一般会直接显示响应体

刷新或者跳转页面

  • ajax请求: 浏览器不会对界面做任何操作,只是调用ajax 请求的函调的回调函数接收到数据

程序员自己操作

ajax的常用API

constructor

  1. The XMLHttpRequest() constructor creates a new XMLHttpRequest.
const xhr= new XMLHttpRequest()

properties

An EventHandler that is called whenever the readyState attribute changes.

Returns an unsigned short, the state of the request.

Returns an ArrayBuffer, Blob, Document, JavaScript object, or a DOMString, depending on the value of XMLHttpRequest.responseType, that contains the response entity body.

It is an enumerated value that defines the response type

Returns a DOMString that contains the response to the request as text, or null if the request was unsuccessful or has not yet been sent.

methods

XMLHttpRequest.open()

Initializes a request.

XMLHttpRequest.setRequestHeader()

Sets the value of an HTTP request header. You must call setRequestHeader()after open(), but before send().


XMLHttpRequest.send()

Sends the request. If the request is asynchronous (which is the default), this method returns as soon as the request is sent.

XMLHttpRequest.open(method, url[, async[, user[, password]]])
  • method

The HTTP request method to use, such as "GET", "POST", "PUT", "DELETE", etc. Ignored for non-HTTP(S) URLs.

  • url

A DOMString representing the URL to send the request to.


XMLHttpRequest.abort()

Aborts the request if it has already been sent.

XMLHttpRequest.getResponseHeader(headerName)

Returns the string containing the text of the specified header, or null if either the response has not yet been received or the header doesn’t exist in the response.

const contentType = xhr.getResponseHeader("Content-Type");

XMLHttpRequest.getAllResponseHeaders()

Returns all the response headers, separated by CRLF, as a string, or null if no response has been received.

function success(text) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = text;
}
function fail(code) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = 'Error code: ' + code;
}
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}
// 发送请求:
request.open('GET', '/api/categories');
request.send();
alert('请求已发送,请等待响应...');

axiosajax的封装

1、axios与Axios的关系

  1. 从语法上来说,axios不是Axios的实例
  2. 从功能上来说,axios是Axios的实例
  • axios 具备 Axios 的 所有方法以及属性
  1. axiosAxios.prototype.request函数bind( ) 返回的函数
  2. axios 作为对象有Axios 原型对象上的所有方法以及Axios 的所有属性
/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  var instance = bind(Axios.prototype.request, context);
  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);
  // Copy context to instance
  utils.extend(instance, context);
  return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Factory for creating new instances
axios.create = function create(instanceConfig) {
    // 合并配置
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');
// Expose isAxiosError
axios.isAxiosError = require('./helpers/isAxiosError');
module.exports = axios;
// Allow use of default import syntax in TypeScript
module.exports.default = axios;
  • Axios 的属性
/**
 * Create a new instance of Axios
 *
 * @param {Object} instanceConfig The default config for the instance
 */
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

2、instance 与 axios 的区别

  1. 相同
  1. 都是Axios 的实例
  2. 都是一个可以发任意请求的函数 request(config)
  3. 具有默认配置和拦截器属性
  1. 不同点
  1. instance 没有axios后面添加的方法 (源码见#1
  2. 也就是通过const instance = axios.create()创建的intance具备Axios的所有方法,但是没有axios
  3. 注意是小写的axios

后面添加的方法,比如Cancel\CancelToken \isCancel 等,具体见 (#1)

3、axios运行的整体流程

  1. 整体流程:

request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)

  1. request(config):

将请求拦截器 / dispatchRequest() / 响应拦截器 通过 promise 链串连起来, 返回 promise

  1. dispatchRequest(config):

转换请求数据 ===> 调用 xhrAdapter()发请求 ===> 请求返回后转换响应数据. 返回 promise

  1. xhrAdapter(config):

创建 XHR 对象, 根据 config 进行相应设置, 发送特定请求, 并接收响应数据, 返回 promise

  • 整体图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dk7YCoPn-1619618181146)(.\pics\image-20210224105956948.png)]

4、 Axios函数

/**
 * Create a new instance of Axios
 *
 * @param {Object} instanceConfig The default config for the instance
 */
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

5、Axios.prototype

/**
 * Dispatch a request
 *
 * @param {Object} config The config specific for this request (merged with this.defaults)
 */
Axios.prototype.request = function request(config) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  if (typeof config === 'string') {
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }
  config = mergeConfig(this.defaults, config);
  // Set config.method
  if (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    config.method = 'get';
  }
    // 拦截器中间件的执行流程
    // reuqest interceptors : [{2},{1}]
    // response interceptors :[{11},{22}]
  // Hook up interceptors middleware
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }
  return promise;
};
Axios.prototype.getUri = function getUri(config) {
  config = mergeConfig(this.defaults, config);
  return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
};
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(mergeConfig(config || {}, {
      method: method,
      url: url,
      data: (config || {}).data
    }));
  };
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(mergeConfig(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

promise chain

while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

6、dispatchRequest

'use strict';
var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');
/**
 * Throws a `Cancel` if cancellation has been requested.
 */
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    config.cancelToken.throwIfRequested();
  }
}
/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */
module.exports = function dispatchRequest(config) {
  throwIfCancellationRequested(config);
  // Ensure headers exist
  config.headers = config.headers || {};
  // Transform request data
  config.data = transformData(
    config.data,
    config.headers,
      // 请求转换器, 源码位于default.js中
    config.transformRequest
  );
  // Flatten headers
  config.headers = utils.merge(
    config.headers.common || {},
    config.headers[config.method] || {},
    config.headers
  );
  utils.forEach(
    ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
    function cleanHeaderConfig(method) {
      delete config.headers[method];
    }
  );
  var adapter = config.adapter || defaults.adapter;
  return adapter(config).then(function onAdapterResolution(response) {
    throwIfCancellationRequested(config);
    // Transform response data
    response.data = transformData(
      response.data,
      response.headers,
      config.transformResponse
    );
    return response;
  }, function onAdapterRejection(reason) {
    if (!isCancel(reason)) {
      throwIfCancellationRequested(config);
      // Transform response data
      if (reason && reason.response) {
        reason.response.data = transformData(
          reason.response.data,
          reason.response.headers,
          config.transformResponse
        );
      }
    }
    return Promise.reject(reason);
  });
};

7、XHR对象 ( axios核心 )

  • axios的部分xhr源码 (Ajax请求)
var request = new XMLHttpRequest();
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
request.onreadystatechange = function handleLoad(){...}
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {...}
 request.onerror = function handleError() {...}
 request.ontimeout = function handleTimeout() {...}
// Send the request
request.send(requestData);

axios取消请求

简介

You can create a cancel token by passing an executor function to the CancelToken constructor:

const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});
// cancel the request
cancel();

Note: you can cancel several requests with the same cancel token.

注意事项

  • cancelToken 的首字母小写
  • new CancelToken(function executor(c) 注意大写

等价于 new CancelToken(c=>{ } )

  • 使用拦截器的时候注意不要定义cancel

拦截器版本

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
  </head>
  <body>
    <button onclick="get()">获取产品1</button>
    <button onclick="post()">获取产品2</button>
    <button onclick="quxiao()">取消请求</button>
    <script>
      const CancelToken = axios.CancelToken;
      let cancel ;
      const instance = axios.create({
        baseURL: "http://localhost:3000",
      });
      instance.interceptors.request.use((config) => {
        if (typeof cancel === 'function') {
            cancel()
        }
        config.cancelToken = new axios.CancelToken(c=>{
            cancel = c
        })
        return config;
      });
      instance.interceptors.response.use(
          response=>{
            cancel = null
            console.log('请求成功')
            return response
          },
          err=>{
            if(axios.isCancel(err)){
                // 取消请求的错误不用处理
                console.log('请求取消的错误',err)
                // 中断promise链
                return new Promise(()=>{})
            }
            else{
                // 请求出错
                console.log('请求1失败了', err)
                // 将错误向下传递
                return Promise.reject(err)
            }
          }
      )
      function get() {
        instance({
          url: "/product1",
        })
          .then((response) => {
            console.log(response);
          })
          .catch(err=>{
            console.log(err)
          })
      }
      function post() {
        instance({
            url:'/product2'
        })
        .then((response) => {
          console.log(response);
        });
      }
      function quxiao() {
        if ((typeof cancel) === 'function') {
            cancel('强制取消请求');
        }else{
            console.log('没有可以取消的请求')
        }
      }
    </script>
  </body>
</html>

菜鸡版本

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
  </head>
  <body>
    <button onclick="get()">获取产品1</button>
    <button onclick="post()">获取产品2</button>
    <button onclick="quxiao()">取消请求</button>
    <script>
      const CancelToken = axios.CancelToken;
      let cancel;
      const instance = axios.create({
        baseURL: "http://localhost:3000",
      });
      function get() {
        if ((typeof cancel) === 'function') {
            cancel('强制取消请求');
        }
        instance({
          url: "/product1",
          cancelToken: new axios.CancelToken(c=>{
                cancel = c
            })
        })
          .then((response) => {
            cancel = null
            console.log(response);
          })
          .catch(err=>{
            if(axios.isCancel(err)){
                // 注意如果在这里将cancel设为null 的话, 会在回调中执行, 导致后一个请求无法取消
                // cancel = null
                console.log('cancel取消请求1发生的错误',err.message)
            }
            else{
                cancel = null
                console.log('发送请求1发生的错误',err.message)
            }
          })
      }
      function post() {
        if ((typeof cancel) === 'function') {
            cancel('强制取消请求');
        }
        instance({
            url:'/product2',
            cancelToken: new axios.CancelToken(c=>{
                cancel = c
            })
        })
        .then((response) => {
            // 请求成功 令牌设null
            cancel = null
            console.log(response);
        })
        .catch(err=>{
            if(axios.isCancel(err)){
                // 注意如果在这里将cancel设为null 的话, 会在回调中执行, 导致后一个请求无法取消
                // cancel = null
                console.log('cancel取消请求2发生的错误',err.message)
            }
            else{
                cancel = null
                console.log('发送请求2发生的错误',err.message)
            }
        })
      }
      function quxiao() {
        if ((typeof cancel) === 'function') {
            cancel('强制取消请求');
        }else{
            console.log('没有可以取消的请求')
        }
      }
    </script>
  </body>
</html>

技术参考:

  1. 尚硅谷
  2. MDN
相关文章
|
1月前
|
资源调度 JavaScript 前端开发
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
这篇文章是关于如何在Vue项目中使用axios进行网络请求、二次封装axios以及使用mockjs模拟响应数据的教程。
77 1
vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
|
6月前
|
前端开发 JavaScript API
JavaScript学习 -- axios的使用
JavaScript学习 -- axios的使用
63 0
|
11月前
|
前端开发 JavaScript API
原来这才是学习axios的正确姿势(安装、使用、跨域代理一站式解决)
Axios 是一个基于 promise 的 异步 ajax 请求库,前端最流行的 ajax 请求库。简单的讲就是可以发送get、post请求,负责与后端交互。
348 1
|
6月前
|
设计模式 前端开发
Promise 与 Axios 的一些学习心得记录
Promise 与 Axios 的一些学习心得记录
53 0
|
JSON 前端开发 API
从零开始学习React-axios获取服务器API接口(五)
从零开始学习React-axios获取服务器API接口(五)
95 0
|
前端开发 JavaScript API
JavaScript学习 -- axios的使用
JavaScript学习 -- axios的使用
69 0
|
JSON 前端开发 JavaScript
Vue学习之利用Axios实现异步通信原理
在前端工作的时候,大部分数据来源都是通过后台传递的json数据来进行前端的数据展示,所以接下来就进行一个模拟Ajax的异步通信。以后可能会用到。
88 0
|
资源调度 前端开发 JavaScript
Axios 请求库入门教程:从零开始学习
Axios 是一个流行的基于 Promise 的 HTTP 请求库,用于在浏览器和 Node.js 中进行 HTTP 请求。
Axios 请求库入门教程:从零开始学习