Vue中统一封装Axios请求

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

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

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)
  })复制代码

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

  • 请求拦截器中的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 参数。后者将优先于前者。

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

一般情况下axios只需要封装post、get请求,这也是很多公司的代码规范,至于为什么不使用其他的请求方式,put(往服务器上传文件),delect(删除)直接对数据进行操作相对来说不安全 。

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

axios虽然是一个插件,但是我们不需要通过Vue.use(axios)来使用,下载完成后,只需在项目中引入即可,如果使用Vue.use()方法的话,则该方法默认会调用install方法,然鹅axios的作者似乎并没有写install的方法。Vue引入的组件类型必须为Function或者是Object。  如果是个对象,必须提供install方法,需要用Vue.use(), 如果是一个函数,会被直接当作install函数执行 

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

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


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

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


最后:我的文章会持续更新完善中···, 如果文章对您有帮助,请点赞^_^,或者留言交流~~



转载于:https://juejin.im/post/5d2f1c54e51d454f6f16eca9

你可能感兴趣的:(json,后端,javascript)