axios 异常处理

8,695 阅读1分钟

interceptors

// Add a request interceptor
axios.interceptors.request.use(function (config) {
  // 这里会最先拿到请求配置,config 对象具体属性见:https://github.com/axios/axios#request-config
  return config;
}, function (error) {
  // 这里极少情况会进来,暂时没有找到主动触发的方法
  return Promise.reject(error);
});

// Add a response interceptor
axios.interceptors.response.use(function (response) {
  // 1. http 状态码是 2xx 会进来这里,response 的数据结构如下:response-200
  // 2. 可通过 validateStatus 配置进到 success callback 的 http status,例如: 
  //    function (status) {
  //      return status >= 200 && status <= 500; // 当 http status 属于定义的范围内,都会进到 success callback
  //    }
  return response;
}, function (error) {
  // 1. http 状态码非2开头(没有额外定义 validateStatus)的都会进来这里,如 404, 500 等,error 的数据结构如下:error-400、error-500
  // 2. 取消请求也会进入这里,可以用 axios.isCancel(error) 来判断是否是取消请求,error 的数据结构如下:cancel-error
  // 3. 请求运行有异常也会进入这里,如故意将 headers 写错:axios.defaults.headers = '123'
  // 4. 断网,error 的数据结构如下:network-error
  return Promise.reject(error);
});

判断 axios error

function onError(e) {
  if (e.response) {
    // 请求已发出,服务器返回的 http 状态码不是 2xx,例如:400,500,对应上面的 1
    console.info(e.response)
  } else if (e.request) {
    // 请求已发出,但没有收到响应,例如:断网,对应上面的 4
    console.info(e.request)
  } else {
    // 请求被取消或者发送请求时异常,对应上面的 2 & 3
    console.info('error', e.message)
  }
  
  return Promise.reject(error);
}

function onSuccess(res) {
  return res
}

axios.interceptors.response.use(onSuccess, onError);

error & response

// error-400
error: {
  config: {…}, // config 对象具体属性见:https://github.com/axios/axios#request-confi
  request: XMLHttpRequest {…}, // 一个 XMLHttpRequest 对象
  response: {
    config: {…},
    data: null,
    headers: {…},
    request: XMLHttpRequest {…},
    status: 400, // HTTP status code
    statusText: "Bad Request", // HTTP status message
  }
  message: "Request failed with status code 400",
  stack: "Error: Request failed with status code 400",
}
// error-500
error: {
  config: {…},
  request: XMLHttpRequest {…}, // 一个 XMLHttpRequest 对象
  response: {
    config: {…},
    data: null,
    headers: {…},
    request: XMLHttpRequest {…},
    status: 500, // HTTP status code
    statusText: "Internal Server Error", // HTTP status message
  }
  message: "Request failed with status code 500",
  stack: "Error: Request failed with status code 500",
}
// network-error
error: {
  config: {…},
  request: XMLHttpRequest {…}, // 一个 XMLHttpRequest 对象
  response: undefined,
  message: "Network Error",
  stack: "Error: Network Error",
}
// cancel-error
error: {
  message: "Operation canceled by the user."
}
// response-200
response: {
  config: {…},
  data: {…}, // 里面是后台自定义的数据结构,例如:{ code, msg, result }
  headers: {…},
  request: XMLHttpRequest {…},
  status: 200, // HTTP status code
  statusText: "OK", // HTTP status message
}

demo

demo: 需要在页面展示一个选择下拉框,数据从接口返回。

<template>
  <el-select v-model="value" placeholder="请选择">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value">
    </el-option>
  </el-select>
</template>

<script>
  import fetchCategories from './api'
  export default {
    data() {
      return {
        options: [],
        value: ''
      }
    },
    methods: {
      getCategories() {
        fetchCategories()
      }
    },
    created() {
      this.getCategories().then(res => {
      	this.options = res
      })
    }
  }
</script>
// api.js
// demo1
export async function fetchCategories() {
  const { data } = await axios.get('/api/mydata/shop/category/')
  return data.result && data.result.list
}

// demo2
export async function fetchCategories() {
  try {
    const { data } = await axios.get('/api/mydata/shop/category/')
    return data.result && data.result.list
  } catch(e) {
    return []
  }
}

如果没有用 try-catch(api.js - demo1),当 axios.get 出错时,程序会停止运行,return xxx 不会被执行,此时函数返回的是一个 pending promise。

因此需要用 try-catch 包裹 await axis.get(xxx)(api.js - demo2),当 axios.get 出错时被 catch,此时函数返回的是一个 promise { status: 'resolved', value: [] },options 被赋值成一个空数组。