Source code analysis of requst library (using axios and interceptor)

Axios usage analysis

The request library uses the manual instantiation method create of axios to encapsulate the request. To understand the usage, we need to learn the usage of the axios library first.

axios basic case

Let's start with a plain axios example:

//npm i -S axios
// 在APP.vue中引入
import axios from 'axios'

const url = 'https://test.youbaobao.xyz:18081/book/home/v2?openId=1234'
axios.get(url).then(response => {
    
    
  console.log(response)
})

The above code can be changed to:

const url = 'https://test.youbaobao.xyz:18081/book/home/v2'
axios.get(url, {
    
     
// params 是一个对象,这个对象可以穿参数 get请求
  params: {
    
     openId: '1234' }
})

We need to add a token in the http header when requesting, and we need to modify the code to:

const url = 'https://test.youbaobao.xyz:18081/book/home/v2'
axios.get(url, {
    
     
  params: {
    
     openId: '1234' },
  //  token
  headers: {
    
     token: 'abcd' }
}).then(response => {
    
    
  console.log(response)
})

If you want to catch the exception thrown by the server, that is, return a non-200 request, you need to modify the code to:

const url = 'https://test.youbaobao.xyz:18081/book/home/v2'
axios.get(url, {
    
     
  params: {
    
     openId: '1234' },
  headers: {
    
     token: 'abcd' }
}).then(response => {
    
    
  console.log(response)
}).catch(err => {
    
    
  console.log(err)
})

This change can meet our needs, but there are two problems:

  • Every request that needs to pass in a token needs to add a headers object, which will cause a lot of repetitive code
  • Each request needs to manually define exception handling, and the logic of exception handling is mostly consistent. If it is encapsulated into a general exception handling method, then each request must be called once. The solution is
    axios.create
axios.create example

It is different from the get method. axios.get is a static method, and axios.create is a dynamic method. That is to say, the result returned by this method is a function. It does not have a specific result. The method generated by axios.creat , you can give him some built-in basic parameters, such as the prefix part of the parameter and timeout, that is, generate a constructor for the fixed part of the request, and then initiate the request through the request

Below we use axios.create to refactor the entire request:

const url = '/book/home/v2'
const request = axios.create({
    
    
  baseURL: 'https://test.youbaobao.xyz:18081', //固定前缀
  timeout: 5000 //超时时间
})
request({
    
     // 直接传入 同样返回promise对象
  url, 
  method: 'get',
  params: {
    
    
    openId: '1234'
  }
})

First, we generate a function through axios.create, which is an instance of axios, and complete the request by executing this method. The difference between it and calling axios.get directly is as follows:

  • The url parameter needs to be passed in, the first parameter of the axios.get method is url
  • The method parameter needs to be passed in, and the axios.get method has indicated that a get request is initiated

Why use this request, because he provides the function of interceptor

axios request interceptor

The above code completes the function of the basic request. Next, we need to add a token to the headers of the http request, and at the same time perform whitelist verification. For example, /login does not need to add a token, and implements asynchronous capture and custom processing:

const whiteUrl = [ '/login', '/book/home/v2' ] // 设置白名单
const url = '/book/home/v2'
const request = axios.create({
    
    
  baseURL: 'https://test.youbaobao.xyz:18081',
  timeout: 5000
})
request.interceptors.request.use( // 有两个方法
  config => {
    
     // 拦截方法
    // throw new Error('error...') 抛出异常 测试
    // 找白名单里有没有  replace 将前缀换为空
    const url = config.url.replace(config.baseURL, '')
    // 如果有就返回
      if (whiteUrl.some(wl => url === wl)) {
    
    
        return config
      }
      // 如果没有就把headers 加上token
    config.headers['token'] = 'abcd'
    return config
  },
  error => {
    
     // 异常处理方法
    return Promise.reject(error)
  }
)
request({
    
    
  url, 
  method: 'get',
  params: {
    
    
    openId: '1234'
  }
}).catch(err => {
    
    
  console.log(err)
})

The core here is to call the request.interceptors.request.use method, which is the request interceptor of axios. This method needs to pass in two parameters. The first parameter is the interceptor method, which contains a config parameter. We can use it in this method Modify the config and send it back. The second parameter is the exception handling method. We can use Promise.reject(error) to return the exception to the user for processing, so we can use catch to catch the exception for custom processing after the request request

axios response interceptor

Let's further enhance the function of axios. In actual development, in addition to ensuring that the http statusCode is 200, we also need to ensure that the business code is correct. In the above case, when I defined error_code as 0, it means that the business returns normally. If the return value is not 0 It means that there is an error in business processing. At this time, we define the response interceptor through the request.interceptors.response.use method. It still needs 2 parameters, which are similar to the request interceptor. Note that the second parameter mainly handles abnormal requests whose statusCode is not 200. The source code is as follows:

const whiteUrl = [ '/login', '/book/home/v2' ]
const url = '/book/home/v2'
const request = axios.create({
    
    
  baseURL: 'https://test.youbaobao.xyz:18081',
  timeout: 5000
})
request.interceptors.request.use(
  config => {
    
    
    const url = config.url.replace(config.baseURL, '')
    if (whiteUrl.some(wl => url === wl)) {
    
    
      return config
    }
    config.headers['token'] = 'abcd'
    return config
  },
  error => {
    
    
    return Promise.reject(error)
  }
)

request.interceptors.response.use(
  response => {
    
    
    const res = response.data
    if (res.error_code != 0) {
    
    
      alert(res.msg)
      return Promise.reject(new Error(res.msg))
    } else {
    
    
      return res
    }
  },
  error => {
    
    
    return Promise.reject(error)
  }
)

request({
    
    
  url, 
  method: 'get',
  params: {
    
    
    openId: '1234'
  }
}).then(response => {
    
    
  console.log(response)
}).catch(err => {
    
    
  console.log(err)
})

request library source code analysis

With the above foundation, it is very easy for us to look at the source code of the request library

const service = axios.create({
    
    
  baseURL: process.env.VUE_APP_BASE_API, //取配置文件当中的url
  timeout: 5000
})

service.interceptors.request.use(
  config => {
    
    
    // 如果存在 token 则附带在 http header 中
    if (store.getters.token) {
    
    
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  error => {
    
    
    return Promise.reject(error)
  }
)

service.interceptors.response.use(
  response => {
    
    
    const res = response.data

    if (res.code !== 20000) {
    
    
      Message({
    
    
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })
      // 判断 token 失效的场景
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
    
    
        // 如果 token 失效,则弹出确认对话框,用户点击后,清空 token 并返回登录页面
        MessageBox.confirm(message:'Token 以失效,是否重新登录',title:'确认登出',options:{
    
    
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
    
    
          store.dispatch('user/resetToken').then(() => {
    
    
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
    
    
      return res
    }
  },
  error => {
    
    
    Message({
    
    
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

Vue admin
login process
interface simplification and routing processing (permission control is realized)
routing and permission verification principle
sidebar
redirection
breadcrumb navigation
requst library axios interception
login component implementation details

Guess you like

Origin blog.csdn.net/qq_52151772/article/details/111354972