Vue中统一封装Axios请求

1.Axios 是什么,为何要统一封装?

axios是一个基于promise的http库,可运行在浏览器端和node.js中。他有不少优秀的特性,例如统一进行拦截请求和响应、取消请求、转换json、客户端防护XSRF等。因此在平常开发中能够直接推荐咱们使用axios库。若是还对axios不了解的,能够移步axios文档。回归正题,咱们所要的说的axios的封装和api接口的统一管理,其实主要目的就是在帮助咱们简化代码和利于后期的更新维护。
node

2.统一封装拦截器和get/post请求

import axios from 'axios'    
import { Loading, Message } from 'element-ui'    // 这里我是使用elementUI的组件来给提示
import router from '@/router'

let loadingInstance = null     // 加载全局的loading

const instance = axios.create({    //建立axios实例,在这里能够设置请求的默认配置
  timeout: 200,
  baseURL: process.env.NODE_ENV === 'production' ? '' : '/api',   //根据本身配置的反向代理去设置不一样环境的baeUrl
  headers: {
    token: sessionStorage.getItem('token') || ''
  }
})
// 文档中的统一设置post请求头。下面会说到post请求的几种'Content-Type'
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

let httpCode = {        //这里我简单列出一些常见的http状态码信息,能够本身去调整配置
  400: '请求参数错误',
  401: '权限不足, 请从新登陆',
  403: '服务器拒绝本次访问',
  404: '请求资源未找到',
  500: '内部服务器错误',
  501: '服务器不支持该请求中使用的方法',
  502: '网关错误',
  504: '网关超时'
}

/** 添加请求拦截器 **/
instance.interceptors.request.use(config => {
  loadingInstance = Loading.service({       // 发起请求时加载全局loading,请求失败或有响应时会关闭
    spinner: 'fa fa-spinner fa-spin fa-3x fa-fw',
    text: '拼命加载中...'
  })
  // 在这里:能够根据业务需求能够在发送请求以前作些什么:例如我这个是导出文件的接口,由于返回的是二进制流,因此须要设置请求响应类型为blob,就能够在此处设置。
  if (config.url.includes('pur/contract/export')) {
    config.headers['responseType'] = 'blob'
  }
  // 我这里是文件上传,发送的是二进制流,因此须要设置请求头的'Content-Type'
  if (config.url.includes('pur/contract/upload')) {
    config.headers['Content-Type'] = 'multipart/form-data'
  }
  return config
}, error=> {
  // 对请求错误作些什么
  return Promise.reject(error)
})

/** 添加响应拦截器  **/
instance.interceptors.response.use(response => {
  loadingInstance.close()
  if (response.data.status === 'ok') {     // 响应结果里的status: ok是我与后台的约定,你们能够根据实际状况去作对应的判断
    return Promise.resolve(response.data)
  } else {
    Message({
      message: response.data.message,
      type: 'error'
    })
    return Promise.reject(response.data.message)
  }
}, error => {
  loadingInstance.close()
  if (error.response) {     
        // 根据请求失败的http状态码去给用户相应的提示
    let tips = error.response.status in httpCode ? httpCode[error.response.status] : error.response.data.message
    Message({
      message: tips,
      type: 'error'
    })
    if (error.response.status === 401) {    // token或者登录失效状况下跳转到登陆页面,根据实际状况,在这里能够根据不一样的响应错误结果,作对应的事。这里我以401判断为例
      router.push({
        path: `/login`
      })
    }
    return Promise.reject(error)
  } else {
    Message({
      message: '请求超时, 请刷新重试',
      type: 'error'
    })
    return Promise.reject(new Error('请求超时, 请刷新重试'))
  }
})

/* 统一封装get请求 */
export const get = (url, params, config = {}) => {
  return new Promise((resolve, reject) => {
    instance({
      method: 'get',
      url,
      params,
      ...config
    }).then(response => {
      resolve(response)
    }).catch(error => {
      reject(error)
    })
  })
}

/* 统一封装post请求  */
export const post = (url, data, config = {}) => {
  return new Promise((resolve, reject) => {
    instance({
      method: 'post',
      url,
      data,
      ...config
    }).then(response => {
      resolve(response)
    }).catch(error => {
      reject(error)
    })
  })
}

/* 或者写成下面这样: Promise.resolve() 和 Promise.reject()返回的是promise对象,两者都是语法糖  */
export const post = (url, data, config = {}) => {
  return instance({
    method: 'post',
    url,
    data,
    ...config
  }).then(response => {
    return Promise.resolve(response)
  }).catch(error => {
    return Promise.reject(error)
  })复制代码

下面几张图是拦截器的回调函数的一些参数:ios

  • 请求拦截器中的config


  • 响应拦截器中的response


  • 响应拦截器中的error


3.统一进行接口api管理

// 每一个模块都应该有本身的接口文件去统一管理api
import { get, post } from '@/utils/request'

export const query = (params) => get('/pur/pay/pageInit', params)复制代码

4.页面上的使用

import { query } from '@/api/index'

export default {
  name: 'App',
  data () {
    return {}
  },
  mounted () {
    let params = { userName: 'admin', password: '123456'}
    query(params).then(res => {
      console.log(res, '这是响应的结果')
    })
  }
}复制代码

5.问题梳理

  • 如何根据不一样的接口去设置不一样的请求头信息,而且有怎样的优先级顺序呢?

能够在请求的拦截器里面config,去判断,分别设置。也可使用已经封装的get/post请求里写,在调用api时,传第三个参数就是config的信息。配置的优先顺序:配置会以一个优先顺序进行合并,  这个顺序是:在 lib/defaults.js 找到的库的默认值,而后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。element-ui

  • 为何只封装了get和post请求?

通常状况下axios只须要封装post、get请求,这也是不少公司的代码规范,至于为何不使用其余的请求方式,put(往服务器上传文件),delect(删除)直接对数据进行操做相对来讲不安全 。json

  • 为何引入axios插件不用Vue.use()

axios虽然是一个插件,可是咱们不须要经过Vue.use(axios)来使用,下载完成后,只需在项目中引入便可,若是使用Vue.use()方法的话,则该方法默认会调用install方法,然鹅axios的做者彷佛并无写install的方法。Vue引入的组件类型必须为Function或者是Object。  若是是个对象,必须提供install方法,须要用Vue.use(), 若是是一个函数,会被直接看成install函数执行 axios

  • 说一说post请求常见的数据格式(Content-Type)

1.application/json : 参数会直接放在请求体中,以JSON格式的发送到后端。这也是axios请求的默认方式。这种类型使用最为普遍。


2.application/x-www-form-urlencoded:请求体中的数据会以普通表单形式(键值对)发送到后端。

3.multipart/form-data 参数会在请求体中,以标签为单元,用分隔符(能够自定义的boundary)分开。既能够上传键值对,也能够上传文件。一般被用来上传文件的格式。


最后:个人文章会持续更新完善中···, 若是文章对您有帮助,请点赞^_^,或者留言交流~~
后端