React学习 --- axios

228 阅读3分钟

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

axios (ajax i/o system) 是目前前端使用非常广泛的网络请求库

主要特点包括:在浏览器中发送 XMLHttpRequests 请求、在 node.js 中发送 http请求、支持 Promise API、拦截请求和 响应、转换请求和响应数据等等

基本使用

get请求

async componentDidMount() {
  try {
    // axios方法返回的都是一个promise
    const res = await axios({
      // get请求的参数可以写在url的地址后边
      // 也可以写在params参数中,让axios库自动进行拼接
      url: 'https://httpbin.org/get',
      params: {
        name: 'Klaus',
        age: 24
      }
    })

    console.log(res)
  } catch(err) {
    console.error(err.message)
  }
}
async componentDidMount() {
  try {
    const res = await axios.request({
      url: 'https://httpbin.org/get',
      params: {
        name: 'Klaus',
        age: 24
      }
    })

    console.log(res)
  } catch(err) {
    console.error(err.message)
  }
}

语法糖写法

 async componentDidMount() {
    try {
      // 参数1: url 参数2: 配置对象
      const res = await axios.get('https://httpbin.org/get', {
        params: {
          name: 'Klaus',
          age: 24
        }
      })
      console.log(res)
    } catch(err) {
      console.error(err.message)
    }
  }

post请求

async componentDidMount() {
  try {
    const res = await axios.request({
      url: 'https://httpbin.org/post',
      data: {
        name: 'Klaus',
        age: 24
      },
      method: 'post' // 默认值是 post
    })

    console.log(res)
  } catch(err) {
    console.error(err.message)
  }
}

语法糖写法

async componentDidMount() {
  try {
    // 参数1: url
    // 参数2:需要传递的data
    // 参数3: 配置对象
    const res = await axios.post('https://httpbin.org/post', {
      name: 'Klaus',
      age: 24
    })
    console.log(res)
  } catch(err) {
    console.error(err.message)
  }
}
async componentDidMount() {
    const request1 = axios.post('https://httpbin.org/post', {
      name: 'Klaus',
      age: 24
    })

    const request2 = axios.get('https://httpbin.org/get', {
      params: {
        name: 'Klaus',
        age: 24
      }
    })

    try {
      // axios.all本质上其实就是Promise.all
      const res = await axios.all([request1, request2])
      console.log(res)
    } catch(err) {
      console.error(err.message)
    }
  }
}

axios可以发送的请求有:

  • axios(config)
  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])

在axios中,任何发送请求的方法,本质上的都是使用axios.request方法发送请求的语法糖形式

axios本质上就是使用axios.request方法进行调用的

// 源码中的部分代码
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  
  // instance就是我们的axios本质上是一个函数
  // 我们直接调用axios方法的时候,本质上就是在调用axios.request方法
  var instance = bind(Axios.prototype.request, context); // Axios.prototype.request.apply(context)
  
  // ....
  
  return instance;
}

var axios = createInstance(defaults);

// bind方法
module.exports = function bind(fn, thisArg) {
  return function wrap() {
    // 这里的args其实就是wrap函数的参数
    // 也就是我们调用axios方法传入的配置对象
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; i++) {
      args[i] = arguments[i];
    }
    return fn.apply(thisArg, args);
  };
};
// axios的所有实例方法本质上调用的就是axios.request
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
    }));
  };
});

修改配置

默认情况下,axios会对我们返回的数据进行封装后再返回

IaONPk.png

而在很多情况下我们可能需要修改axios请求的默认配置

那么我们可以在入口文件中,对axios.defaults(也就是axios的默认配置信息)进行修改

index.js

import axios from 'axios'

// 修改baseURL
axios.defaults.baseURL = 'https://httpbin.org/'

// 任何请求都需要使用到的请求头配置
axios.defaults.headers.common['token'] = 'c9H1Vsb5tkAyqeW7FNKnH3Wqbw9Nl4JT';

// 单独请求特有的请求头单独配置
axios.defaults.headers.get.FOO = 'foo';

如果我们存在多个服务器的时候,我们可以使用axios.create方法创建多个axios实例来处理不同的服务器请求和响应

const api = axios.create({
  baseURL: 'http://api.example.com/',
  headers: Object.assign(axios.defaults.headers, {
    common: {
      token: 'c9H1Vsb5tkAyqeW7FNKnH3Wqbw9Nl4JT'
    }
  })
})

const one = axios.create({
  baseURL: 'http://api-one.example.com/'
})
one.defaults.headers.common.token = 'gnS5OgNDtReokJbwgb7Sbki3RRhXLlPf'

如果存在多个配置项,那么他们之间的优先级是:

  1. 优先是请求的config参数配置

  2. 其次是实例的default中的配置

  3. 最后是创建实例时的配置

拦截器

我们可以使用axios的拦截器对axios的请求和响应进行拦截处理

// 请求拦截
// 参数1: onFulliflled
// 参数2: onRejected
axios.interceptors.request.use(config => {
  // 1. 我们可以在这里加载请求中的loading
  // 2. 我们可以在这里进行有没有token的判断 --- 鉴权操作
  // 3. 我们对我们请求的参数进行二次转换

  console.log(`向${config.url}发送了${config.method}请求`)

  // 需要将配置选项传递给下一个方法进行使用的
  return config
}, error => error) // 错误直接传递,不进行任何的处理 --- 不做处理其实是可以省略的

// 响应拦截
axios.interceptors.response.use(res => {
  // 直接返回服务器真正返回我们的数据
  return res.data
})

简单封装

默认情况下我们是可以直接使用axios来进行开发的

但是在实际开发中,我们会存在许多个文件中都需要使用到axios来进行网络请求

此时,如果某一天,我们需要对axios的配置进行调整,或者使用别的库来替换axios的时候

我们就需要去修改所有引入了axios的js文件,此时工作量和出错率都是很大的

所以我们在实际开发过程中,我们都会自己将axios请求进行二次封装

然后在项目代码中使用我们封装后的API

这样如果以后需要修改后替换axios的时候,就只要修改我们自己封装的哪几个js文件就可以了

IieGwO.png

src/service/consts.js

const devBaseURL = 'https://api-sit.example.com/'
const prodBaseURL = 'https://api.example.com/'

export const BASEURL = process.env.NODE_ENV === 'development' ? devBaseURL : prodBaseURL

export const TIMEOUT = 5000

src/service/api.js

import axios from 'axios'

import { BASEURL, TIMEOUT } from './consts'

const api = axios.create({
  baseURL: BASEURL,
  timeout: TIMEOUT
})

api.interceptors.response.use(res => res.data)

export default api

使用

    api.post('http://httpbin.org/post', {
      name: 'Klaus',
      age: 24
    })
    .then(res => console.log(res))
    .catch(console.log) 
// 因为catch需要传递一个callback,参数会传递res
// 而console.log本质就是一个函数,其也可以接收一个或多个参数
// 所以我们可以在这里直接将console.log函数进行传入,作为onReject函数