本篇文章将对项目中如何封装axios常用的请求方法进行介绍,其中包括最容易出问题的post请求的解释,包括一些请求格式和参数格式不一致问题的解决;


通用配置

这些配置是在axios官方文档中没有列出来的,主要是post方法的内容类型的定义,不配置的话经常会出现请求提交失败或者数据没有正常提交的问题,这些一般都是前后端采用的post的数据格式不一致导致的。

axios.defaults.timeout = 15000;  //超时响应
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 配置请求头(推荐)
// axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8'; // 配置请求头
axios.defaults.baseURL = $core.use('http'); //确认协议和地址
axios.defaults.withCredentials = true;   // axios 默认不发送cookie,需要全局设置true发送cookie

1. get请求

axios中常见的get/delete请求,也称作query请求:

一般发送请求是这么写(不推荐):

axios.get('/user?id=12345&name=user')
.then(function (res) {
    console.log(res);
}).catch(function (err) {
    console.log(err);
});

但是为了方便全局统一调用封装的axios,我一般采用(推荐)

axios.get('/user', {  //params参数必写 , 如果没有参数传{}也可以
    params: {  
       id: 12345,
       name: user
    }
})
.then(function (res) {
    console.log(res);
})
.catch(function (err) {
    console.log(err);
});

2. post/put/patch请求

传参方式大致用的有3种

(1) 传参格式为 formData

(全局请求头:‘Content-Type’= ‘application/x-www-form-urlencoded’)

(request的Header:‘Content-Type’= ‘multipart/form-data’)

var formData=new FormData();
formData.append('user',123456);
formData.append('pass',12345678);
 
axios.post("/notice",formData)
     .then((res) => {return res})
     .catch((err) => {return err})
 

(2) 传参格式为 query 形式

全局请求头:‘Content-Type’= ‘application/x-www-form-urlencoded’)

(request的Header:‘Content-Type’= ‘application/x-www-form-urlencoded’)

第一种情况:使用$qs.stringify

import Qs from 'qs'   //引入方式
Vue.prototype.$qs = Qs  //全局加载
this.$qs.stringify(data);  //使用方式
this.$qs.parse(data);  //使用方式
 
var readyData=this.$qs.stringify({
    id:1234,
    name:user
});
axios.post("/notice",readyData)
     .then((res) => {return res})
     .catch((err) => {return err})

(3) 传参格式为raw (JSON格式)

第一种情况: axios将JavaScript对象序列化为JSON

(全局请求头:‘Content-Type’= ‘application/x-www-form-urlencoded’)

(request的Header:‘Content-Type’= ‘application/json;charset=UTF-8’)

var readyData={
    id:1234,
    name:user
};
axios.post("/notice",readyData)
     .then((res) => {return res})
     .catch((err) => {return err})

第二种情况:

(全局请求头:‘Content-Type’= ‘application/json;charset=UTF-8’)

(request的Header:‘Content-Type’= ‘application/json;charset=UTF-8’)

var readyData=JSON.stringify({
    id:1234,
    name:user
});
axios.post("/notice",readyData)
     .then((res) => {return res})
     .catch((err) => {return err})

下面给出常用方法的封装,可以直接用在项目中,并列出了可能会遇到的问题解决

下面所有的提示都是基于iview的提示控件,但是一个项目如果有多个UI库就会引起很多冲突,所以建议大家只用一个UI组件库,根据自己项目情况修改提示。

/** axios封装
 * 请求拦截、相应拦截、错误统一处理
 */
// import service from 'axios'
import axios from 'axios'
import QS from 'qs'
// import { Toast } from 'vant'
import router from '@/router'
import store from '../store/index'
let serviceConfig = 'http://192.168.31.69:8080'

// const axios = service.create({
//   baseURL: serviceConfig // api的base_url
//   /* baseURL: "http://192.168.0.107:9090", */ // api的base_url
// })
// 环境的切换
if (process.env.NODE_ENV === 'development') {
  axios.defaults.baseURL = serviceConfig // 'api'
  //   axios.defaults.baseURL = 'api'
} else if (process.env.NODE_ENV === 'debug') {
  axios.defaults.baseURL = ''
} else if (process.env.NODE_ENV === 'production') {
  axios.defaults.baseURL = serviceConfig
  //   axios.defaults.baseURL = '/api'
}

// 请求超时时间
axios.defaults.timeout = 2000

// post请求头
axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded;charset=UTF-8'
// 请求拦截器
axios.interceptors.request.use(
  config => {
    // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
    // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
    config.withCredentials = true
    const token = store.state.token
    token && (config.headers.Authorization = token)
    return config
  },
  error => {
    return Promise.error(error)
  }
)

// 响应拦截器
axios.interceptors.response.use(
  response => {
    if (response.status === 200) {
      return Promise.resolve(response)
    } else {
      return Promise.reject(response)
    }
  },
  // 服务器状态码不是200的情况
  error => {
    if (error.response.status) {
      switch (error.response.status) {
        // 401: 未登录
        // 未登录则跳转登录页面,并携带当前页面的路径
        // 在登录成功后返回当前页面,这一步需要在登录页操作。
        case 401:
          router.replace({
            path: '/login',
            query: { redirect: router.currentRoute.fullPath }
          })
          break
        // 403 token过期
        // 登录过期对用户进行提示
        // 清除本地token和清空vuex中token对象
        // 跳转登录页面
        case 403:
          this.$Modal.info({
            content: '登录过期,请重新登录',
            duration: 1
          })
          // 清除token
          localStorage.removeItem('token')
          store.commit('loginSuccess', null)
          // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
          setTimeout(() => {
            router.replace({
              path: '/login',
              query: {
                redirect: router.currentRoute.fullPath
              }
            })
          }, 1000)
          break
        // 404请求不存在
        case 404:
          this.$Modal.erro({
            content: '网络请求不存在',
            duration: 1
          })
          break
        // 其他错误,直接抛出错误提示
        default:
          this.$Modal.erro({
            content: error.response.data.message,
            duration: 1.5
          })
      }
      return Promise.reject(error.response)
    }
  }
)
/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export const get = (url, ...params) => {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params
      })
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}
/**
 * post方法,对应post请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export const post = (url, ...params) => {
  return new Promise((resolve, reject) => {
    axios //QS.stringify(params)关于这个函数会输出什么结果大家可以自行尝试一下,结果会让你惊喜,也可以自己单独传一个对象进去测试一下
      .post(url, QS.stringify(...params))
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}
/**
 * delet方法,对应delett请求
 * @param {String} url [请求的url地址]
 * delete关键字会和vue系统关键字冲突,所以这里用delet代替
 * delete用于删除,参数一般带在url
 */
export const delet = url => {
  return new Promise((resolve, reject) => {
    axios
      .delete(url)
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}
/**
 * patch方法,对应patch请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 * 这里根据需求适应了formdata的格式,也可以跟post用一样的封装
 */
export const patch = (url, params) => {
// 将数据转换为formData格式
// 正常情况下可以直接使用参数对象进行patch,如果出错可以尝试转换form Data
  var formData = new FormData()
  formData.append('username', params.username)
  formData.append('password', params.password)
  return new Promise((resolve, reject) => {
    axios
      .patch(url, formData)
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

Logo

前往低代码交流专区

更多推荐