Vue中统一封装Axios请求

亦凉 2024-04-17 06:29 170阅读 0赞

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

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

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

  1. import axios from 'axios'
  2. import { Loading, Message } from 'element-ui' // 这里我是使用elementUI的组件来给提示
  3. import router from '@/router'
  4. let loadingInstance = null // 加载全局的loading
  5. const instance = axios.create({ //创建axios实例,在这里可以设置请求的默认配置
  6. timeout: 200,
  7. baseURL: process.env.NODE_ENV === 'production' ? '' : '/api', //根据自己配置的反向代理去设置不同环境的baeUrl
  8. headers: {
  9. token: sessionStorage.getItem('token') || ''
  10. }
  11. })
  12. // 文档中的统一设置post请求头。下面会说到post请求的几种'Content-Type'
  13. instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
  14. let httpCode = { //这里我简单列出一些常见的http状态码信息,可以自己去调整配置
  15. 400: '请求参数错误',
  16. 401: '权限不足, 请重新登录',
  17. 403: '服务器拒绝本次访问',
  18. 404: '请求资源未找到',
  19. 500: '内部服务器错误',
  20. 501: '服务器不支持该请求中使用的方法',
  21. 502: '网关错误',
  22. 504: '网关超时'
  23. }
  24. /** 添加请求拦截器 **/
  25. instance.interceptors.request.use(config => {
  26. loadingInstance = Loading.service({ // 发起请求时加载全局loading,请求失败或有响应时会关闭
  27. spinner: 'fa fa-spinner fa-spin fa-3x fa-fw',
  28. text: '拼命加载中...'
  29. })
  30. // 在这里:可以根据业务需求可以在发送请求之前做些什么:例如我这个是导出文件的接口,因为返回的是二进制流,所以需要设置请求响应类型为blob,就可以在此处设置。
  31. if (config.url.includes('pur/contract/export')) {
  32. config.headers['responseType'] = 'blob'
  33. }
  34. // 我这里是文件上传,发送的是二进制流,所以需要设置请求头的'Content-Type'
  35. if (config.url.includes('pur/contract/upload')) {
  36. config.headers['Content-Type'] = 'multipart/form-data'
  37. }
  38. return config
  39. }, error=> {
  40. // 对请求错误做些什么
  41. return Promise.reject(error)
  42. })
  43. /** 添加响应拦截器 **/
  44. instance.interceptors.response.use(response => {
  45. loadingInstance.close()
  46. if (response.data.status === 'ok') { // 响应结果里的status: ok是我与后台的约定,大家可以根据实际情况去做对应的判断
  47. return Promise.resolve(response.data)
  48. } else {
  49. Message({
  50. message: response.data.message,
  51. type: 'error'
  52. })
  53. return Promise.reject(response.data.message)
  54. }
  55. }, error => {
  56. loadingInstance.close()
  57. if (error.response) {
  58. // 根据请求失败的http状态码去给用户相应的提示
  59. let tips = error.response.status in httpCode ? httpCode[error.response.status] : error.response.data.message
  60. Message({
  61. message: tips,
  62. type: 'error'
  63. })
  64. if (error.response.status === 401) { // token或者登陆失效情况下跳转到登录页面,根据实际情况,在这里可以根据不同的响应错误结果,做对应的事。这里我以401判断为例
  65. router.push({
  66. path: `/login`
  67. })
  68. }
  69. return Promise.reject(error)
  70. } else {
  71. Message({
  72. message: '请求超时, 请刷新重试',
  73. type: 'error'
  74. })
  75. return Promise.reject(new Error('请求超时, 请刷新重试'))
  76. }
  77. })
  78. /* 统一封装get请求 */
  79. export const get = (url, params, config = {}) => {
  80. return new Promise((resolve, reject) => {
  81. instance({
  82. method: 'get',
  83. url,
  84. params,
  85. ...config
  86. }).then(response => {
  87. resolve(response)
  88. }).catch(error => {
  89. reject(error)
  90. })
  91. })
  92. }
  93. /* 统一封装post请求 */
  94. export const post = (url, data, config = {}) => {
  95. return new Promise((resolve, reject) => {
  96. instance({
  97. method: 'post',
  98. url,
  99. data,
  100. ...config
  101. }).then(response => {
  102. resolve(response)
  103. }).catch(error => {
  104. reject(error)
  105. })
  106. })
  107. }
  108. /* 或者写成下面这样: Promise.resolve() 和 Promise.reject()返回的是promise对象,二者都是语法糖 */
  109. export const post = (url, data, config = {}) => {
  110. return instance({
  111. method: 'post',
  112. url,
  113. data,
  114. ...config
  115. }).then(response => {
  116. return Promise.resolve(response)
  117. }).catch(error => {
  118. return Promise.reject(error)
  119. })复制代码

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

  • 请求拦截器中的config
  • 响应拦截器中的response
  • 响应拦截器中的error

3.统一进行接口api管理

  1. // 每个模块都应该有自己的接口文件去统一管理api
  2. import { get, post } from '@/utils/request'
  3. export const query = (params) => get('/pur/pay/pageInit', params)复制代码

4.页面上的使用

  1. import { query } from '@/api/index'
  2. export default {
  3. name: 'App',
  4. data () {
  5. return {}
  6. },
  7. mounted () {
  8. let params = { userName: 'admin', password: '123456'}
  9. query(params).then(res => {
  10. console.log(res, '这是响应的结果')
  11. })
  12. }
  13. }复制代码

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

发表评论

表情:
评论列表 (有 0 条评论,170人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Vue统一封装Axios请求

    1.Axios 是什么,为什么要统一封装? axios是一个基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如统一进行拦截请...

    相关 vue-封装axios请求

    最近接手新的vue项目,发现axios竟然没有封装,立马动手封装,这里记录一下完整的封装过程,废话不说,直接上代码 baseConfig.js文件 //存放各个服