axios使用与源码分析

HTTP相关

一、不同类型的请求

​ GET: 从服务器端读取数据

​ POST: 向服务器端添加新数据

​ PUT: 更新服务器端已经数据 (不能接受 query 参数,只能接受 params 参数)

​ DELETE: 删除服务器端数据 (不能接受 query 参数,只能接受 params 参数)

query 参数 : localhost:8080/path?name=xxx&age=xxx

params 参数 : localhost:8080/path/xxx

二、REST 与 非REST

1. REST(restful) API

  • 发送请求进行CRUD哪个操作由请求方式来决定

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

  • 请求方式会用到GET/POST/PUT/DELETE

2. 非REST(restful) API

  • 请求方式不决定请求的CRUD操作
  • 一个请求路径只对应一个操作
  • 一般只有GET/POST

3、使用 json-server

可以使用 json-server 快速搭建模拟 REST API,在线文档:https://github.com/typicode/json-server

1、npm install -g json-server

2、目标根目录下创建数据库json文件: db.json

​ {

​ “posts”: [

​ { “id”: 1, “title”: “json-server”, “author”: “typicode” }

​ ],

​ “comments”: [

​ { “id”: 1, “body”: “some comment”, “postId”: 1 }

​ ],

​ “profile”: { “name”: “typicode” }

​ }

3、启动服务器执行命令:json-server --watch db.json

三、一般http请求与ajax请求

在这里插入图片描述

  1. ajax请求是一种特别的http请求

  2. 对服务器端来说, 没有任何区别, 区别在浏览器端

  3. 浏览器端发请求: 只有XHR或fetch函数发出的才是ajax请求;其它所有的都是非ajax请求,包括 < a > 、location 、< img >

  4. 浏览器端接收到响应

    (1) 一般请求: 浏览器一般会直接显示响应体数据, 也就是我们常说的刷新/跳转页面,

    (2)ajax请求: 浏览器不会对界面进行任何更新操作, 只是调用监视的回调函数并传入响应相关数据(需要手动写代码通过DOM操作和css操作对界面进行局部更新) ,前端可以获取到数据,而无需让整个的页面刷新,这使得Web页面可以只更新页面的局部,而不影响用户的操作。

Axios

文档: http://axios-js.com/zh-cn/docs/

特点

  1. 基于xhr + promise的异步ajax请求库

  2. 浏览器端/node端都可以使用

  3. 支持请求/响应拦截器

  4. 支持请求取消

  5. 请求/响应数据转换

  6. 批量发送多个请求

常用语法

axios(config): 通用/最本质的发任意类型请求的方式

axios(url[, config]): 可以只指定url发get请求

axios.request(config): 等同于axios(config)

axios.get(url[, config]): 发get请求

axios.delete(url[, config]): 发delete请求

axios.post(url[, data, config]): 发post请求

axios.put(url[, data, config]): 发put请求


axios.defaults.xxx: 请求的默认全局配置


axios.interceptors.request.use(): 添加请求拦截器

axios.interceptors.response.use(): 添加响应拦截器


axios.create([config]): 创建一个新的axios(它没有下面的功能)


axios.Cancel(): 用于创建取消请求的错误对象

axios.CancelToken(): 用于创建取消请求的token对象

axios.isCancel(): 是否是一个取消请求的错误

axios.all(promises): 用于批量执行多个异步请求

axios.spread(): 用来指定接收所有成功数据的回调函数的方法

用法

1、基本用法

axios({
        url:'http://localhost:3000/posts',
        method: 'get',
        params:{
          id : 1,
          name : 'Susan'
        }
      }).then(
        response => {
          console.log(response.data)
        },
        error => {
          console.log(error.message);
        }        
      )
axios({
        url: 'http://localhost:3000/posts',
        method : 'post',
        data : {
          id : 4,
          name : 'Tom'
        }
      }).then(
        response => {
          console.log(response.data)
        },
        error => {
          console.log(error);          
        }
      )
axios({
        url : 'http://localhost:3000/posts/4',
        method : 'put',
        data : {
          id : 4,
          title : 'hi'
        }
      }).then(
        response => {
          console.log(response.data);
        },
        error => {
          console.log(error);
          
        }        
      )
axios({
        url : 'http://localhost:3000/posts/4',
        method : 'delete',
      }).then(
        response => {
          console.log(response.data);
        },
        error => {
          console.log(error);
          
        }        
      )

2、多并发请求

function getUserAccount() {
  return axios.get('/user/12345');
}
 
function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));

3、Axios 基本封装

function myAxios({url , method='get' , params={} , data={}}){
        return new Promise((resolve , reject) => {
          let str = '';
          for (var i in params) {
              str += i + '=' + params[i] + '&';
          }
          //移除最后一个 &
          str = str.substr(0, str.length -1);
          url = url+'?'+str;

          let xhr = new XMLHttpRequest();
            //初始化
          xhr.open(method , url , true)
			//绑定事件
          xhr.oneadystatechange = function(){

            if(xhr.readyState === 4){
              if(xhr.status >= 200 && xhr.status < 300){
                let res = {
                  data : JSON.parse(xhr.response),
                  status
                }
                resolve(res)
              }else{
                reject(new Error('request error status is ' + status))
              }
            }
          }
			//发送
          if(xhr.method === 'get'){
            xhr.send()
          }else{
            xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8') // 告诉服务器请求体的格式是json
            xhr.send(JSON.stringify(data))
          }
        })
      }


-----------------------------
    myAxios({
        url:'http://localhost:3000/post',
        method : 'get',
        params:{
          "title": "ccccccc",
          "id": "H9unEzl"
        }
      }).then(
        (response) => {
          console.log(response); //response就是res对象
        },
        (error) => {
          console.log(error);
        }
      )

4、拦截器

(1)说明: 调用axios()并不是立即发送ajax请求, 而是需要经历一个较长的流程

(2)流程: 请求拦截器2 => 请求拦截器1 => 发ajax请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调

(3)注意: 此流程是通过promise串连起来的, 请求拦截器传递的是config, 响应拦截器传递的是response

用途:loding效果

​ token进行用户权限认证

  <script src="https://cdn.bootcss.com/axios/0.19.2/axios.js"></script>
  <script src="https://cdn.bootcss.com/nprogress/0.2.0/nprogress.js"></script>


	axios.interceptors.request.use(
      config => {
        //loading
        NProgress.start()
        // console.log(config)

        //token
        //localStorage.getItem()  ????
        const t = 'abc';
        if(t){
          config.headers['token'] = t;
          // config.headers.Authorization = t;
        }
        return config
      }
    )

    axios.interceptors.response.use(
      response => {
        NProgress.done()
        return response.data
      },
      error => {
        NProgress.done()
        //情况1:
        return Promise.reject(error)
        // throw error
        //情况二:
        //中断promise链,下级不处理错误,统一在这里处理
        // console.log(error.message);
        // return new Promise(() => {})
      }
    )


    function getAxios(){
      axios.get('http://localhost:3000/posts')
          .then(
            (resolve) => {
              console.log(resolve)
            },
            (error) => {
              console.log(error.message);

            }
          )
    }
import axios from 'axios'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import store from '@/store'

const service = axios.create({
  baseURL : "/api",
  timeout : 15000
})

service.interceptors.request.use((config)=>{
  NProgress.start();

  config.headers['userTempId'] = store.state.user.userTempId
  
  const token = store.state.user.userInfo.token
  if(token){
    config.headers['token'] = token
  }

  return config
})

service.interceptors.response.use(
  response =>{
    NProgress.done()
    return response.data
  },
  error => {
    console.log(error.message)
    return Promise.reject(error)
  }
)

export default service

5、取消请求

axios.interceptors.request.use((config) => {
      if(typeof cancel === 'function'){
        cancel('取消未完成请求')
      }

      config.cancelToken = new axios.CancelToken((c) => {
        cancel = c;
      })

      return config
    })

    axios.interceptors.response.use(
      resolve => {
        cancel = null
        return resolve
      },
      error => {
        if (axios.isCancel(error)) {
          console.log('取消请求:', error.message);
        } else {
          cancel = null
          return Promise.reject(error)
        }
      }
    )


    let cancel;
	//发送axios请求
    function request1(){
      
      axios.get('http://localhost:4000/getProducts1')
          .then(
            (resolve) => {
              console.log('请求1成功:',resolve)
            },
            (error) => {
              console.log('请求1失败:',error.message);
            }
          )
    }

	//发送axios请求
    function request2(){
      axios.get('http://localhost:4000/getProducts2')
          .then(
            (resolve) => {
              console.log('请求2成功:',resolve)
            },
            (error) => {
              console.log('请求2失败:',error.message);
            }
          )
    }
	//点击按钮执行cancelReq函数,进行强制取下请求
    function cancelReq(){
      if(typeof cancel === 'function'){
        cancel('取消请求成功');
      }else{
        console.log('没有请求');
      }
    }

axios源码解析

一、axios与Axios的关系

源码:

axios.js
在这里插入图片描述
在这里插入图片描述
E:\尚硅谷课程\git\课件\assets\image-20200321123412875.png

Axios.js
E:\尚硅谷课程\git\课件\assets\image-20200321124711833.png
在这里插入图片描述
总结:

createInstance()函数返回(return)了 instance()函数,而 instance 函数 = Axios.prototype.request.bind(context),instance 函数调用的就是 Axios 原型上的 request 方法,内部的 this 指向 context —— Axios 的实例。

axios 和 axios.create 就是 instance,就是 Axios.prototype.request。

当调用 axios.get 、axios.post 方法是,就是调用的 Axios.prototype.request 上的 get 、post 方法。

Axios.prototype 上的方法有 request()、get()、post()、put()、delete() ,并将这些方法通过 extend 函数都拷贝到了 instance 上。

Axios 的实例对象上有 defaults、interceptors 属性,这些属性也通过 extend 函数都拷贝到了 instance 上。

所以 axios 和 axios.create 作为对象有 Axios.prototype 上的所有方法, 有 Axios 的实例对象 上所有属性。

从语法上来说: axios不是Axios的实例

从功能上来说: axios是Axios的实例

二、axios与instance的区别

  1. 相同:

(1) 都是一个能发任意请求的函数: request(config)

(2) 都有发特定请求的各种方法: get()/post()/put()/delete()

(3) 都有默认配置和拦截器的属性: defaults/interceptors

  1. 不同:

(1) 默认配置很可能不一样

(2) instance没有axios后面添加的一些方法: create()/ Cancel()/ CancelToken()/ isCancel()/ all()

三、axios运行的整体流程

E:\尚硅谷课程\git\课件\assets\image-20200321125546307.png

核心函数执行顺序:

request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)
E:\尚硅谷课程\git\课件\assets\image-20200321131242838.png

  1. request(config):

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

interceptors.request 请求拦截器是用 unshift 添加在 chain 数组前的,所以执行的时候,后添加的会先执行。

interceptors.response 响应拦截器是用 push 添加在 chain 数组后的,所以执行的时候,先添加的先执行。

Axios.js 源码:
在这里插入图片描述
在这里插入图片描述
2. dispatchRequest(config):

转换请求数据 (transformRequest) ==>

return adapter ==> 调用 xhrAdapter() 发请求 ==>

请求返回后转换响应数据(transformResponse) ==> 返回promise

dispatchRequest.js源码:
在这里插入图片描述
defaults.js 源码:
E:\尚硅谷课程\git\课件\assets\image-20200423161408435.png
defaults.js 源码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. xhrAdapter(config):

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

四、取消未完成的请求

  1. 当配置了cancelToken对象时, 保存cancel函数

(1) 创建一个用于将来中断请求的cancelPromise

(2) 并定义了一个用于取消请求的cancel函数

(3) 将cancel函数传递出来

  1. 调用cancel()取消请求

(1) 执行cancel函数, 传入错误信息message

(2) 内部会让cancelPromise变为成功, 且成功的值为一个Cancel对象

在cancelPromise的成功回调中中断请求, 并让发请求的proimse失败, 失败的reason为Cacel对象


CancelToken.js 源码:
在这里插入图片描述

xhr.js源码:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值