用axios扩展出一个适合自己项目的ajax工具类

前言

之前在用vue写项目的时候对axios做了一层封装,写了一篇文章 vue中用axios post方式报错的解决方法;最近在做一个react的项目时与同事交流的过程中发现之前那样的做法并不好,所以,现在要对之前的做法做一些改进。

改进点

1、主要是在axios上进行扩展,而不是修改axios本身。
2、新加post 的content-type: application/json的提交方式;
3、对form表单提交做了扩展,支持普通对象参数与及formData对象,(formData对象适于ajax上传图片)
新建一个ajax.js

import axios from 'axios'
import qs from 'qs'

const TIME_OUT = 30000 // 超时时间30秒

// 请求数据拦截处理
axios.interceptors.request.use(config => {
// code... 你的逻辑
  return config
}, error => {
  return Promise.reject(error)
})

// 返回数据拦截处理
axios.interceptors.response.use(response => {
  //code... 你的逻辑
  return response.data //直接返回后台返回的json object
}, error => Promise.reject(error.response))

/*
* 封装一个私有的请求方法
*/
const _request = (method, url, data) => {
  const headers = {}
  const configData = {
    url, // 请求的地址
    timeout: TIME_OUT, // 超时时间, 单位毫秒
    headers
  }

  if (method === 'get') {
    configData.method = 'get'
    configData.params = data// get 请求的数据
  } else if (method === 'postForm') {
    configData.method = 'post'
    if (Data instanceof FormData) {
      configData.headers['Content-Type'] = 'multipart/form-data; charset=UTF-8'
      configData.data = data
    } else {
      configData.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
      configData.data = qs.stringify(data)
    }
  } else if (method === 'postJson') {
    configData.method = 'post'
    configData.headers['Content-Type'] = 'application/json; charset=UTF-8'
    configData.data = data
  }

  return axios(configData)
}

class Ajax {
  get = (url, data = {}) => {
    return _request('get', url, data)
  }

  postForm = (url, data = {}) => {
    return _request('postForm', url, data)
  }

  postJson = (url, data = {}) => {
    return _request('postJson', url, data)
  }

  post = this.postJson // 默认post的Content-Type是application/json
}

export default new Ajax()

上面的代码首先 封装一个私有的请求方法(_request),由于开发前后端联调期间,肯定是跨域的,我们就采用cors方法,并且我们的后端在接口中要用到cookie,所以必须设置withCredentials: true;然后再 建一个Ajax class class里面定义了项目需要的请求方法。主要有三个:
get,
postJson,
postForm,
默认post === postJson,我们的post请求默认就是 'Content-Type: application/json; charset=UTF-8'的,与后端的联调时也踩了几个坑,
主要是后端没有配合对应的response header:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin: 'localhost:3000'
Access-Control-Allow-Headers: 'content-type'

在response headers里面必须要有上面三个字段,第一个是允许跨域cookie的,第二个就是你的本地开发服务的域名端口,后端同学可以在request headers的origin字段里面拿,Access-Control-Allow-Origin不可以为'*',因为 '*' 会和 Access-Control-Allow-Credentials:true 冲突,需配置指定的地址;最重要就是第三个Access-Control-Allow-Headers: 'content-type',因为我们的项目的post请求默认是用了content-type:application/json形式的,而在跨域的情况下,如果前端设置的request headers的content-type里面如果不是以下三个值之一

application/x-www-form-urlencoded
multipart/form-data
text/plain

浏览器就会在每次ajax请求时都会发一个基于options方式的预检请求去询问服务端是否接收请求,这时候Access-Control-Allow-Headers: 'content-type'就起到作用了,不然预检请求都不通过,更不用说预检请求之后的正式请求了。

用法

定义好ajax之后就要用了:

//在你要发请求的地方引入
import Ajax from './ajax'
const url = 'xxx.com/xxx/xxx'
const data = {key1: 'value1',key2: 'value2'}
// get
Ajax.get(url,data).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})

// post with content-type:application/json
Ajax.post(url,data).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})
// or
Ajax.postJson(url,data).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})

// post with  content-type:application/x-www-form-urlencoded
Ajax.postForm(url,data).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})

// post with  formData,
// 如上传图片
const formData = new FormData()
formData.append('file', this.file) // this.file是input type='file'选中的图片

Ajax.postForm(url,formData).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})



经过这次修改之后,以后在每个项目中都可以这样用了。

如果在vue中你还可以直接把挂载在vue.prototype上,就不用每次都去导入,

// export default new Ajax()
Vue.prototype.$ajax = new Ajax()

// 用到就直接this.$ajax.get()
this.$ajax.get(url,data).then(res => {
// 你的逻辑
}).catch(err => {
// 你的逻辑
})

甚至你可以做成一个插件的形式,在ajax.js中最后导出一个函数

// ajax.js
export default (Vue) => {
  if (typeof window !== 'undefined' && window.Vue) {
    Vue = window.Vue
  }
  Vue.prototype.$ajax = new Ajax()
}

然后在main.js中这么写

import Vue from 'vue'
import Ajax from './ajax'

Vue.use(Ajax)

推荐阅读更多精彩内容