axios 使用心得

从刚开始接触 Vue 时,官方维护了一个 request 项目是 vue-resource ,后来推荐使用社区的 axios 来作为 request 工具。

两者之间的区别:

  1. axios支持服务端(Node中自带的 request 包并不支持promise,通常需要使用bluebird来进行promise化),resource不支持服务端
  2. axios 功能更加丰富,支持 Intercept 功能。

刚开始使用axios 的时候,只会在 main.js 中统一配置

Vue.prototype.$http = axios

然后就按照之前Vue-resource的写法进行书写,在小项目中这样使用也确实没有提现出axios
的优势。

在17年11月进行的创天下项目中,遇到了很多关于 权限校验 及一些数据格式转化的问题。

数据格式

axios 默认的是以 JSON 数据格式来传输的。
而常见的POST提交数据的格式有四种,分别是:

  1. application/x-www-form-urlencodeed
  2. multipart/form-data
  3. application/json
  4. text/xml

    而创天下项目中使用的基本都是application/x-www-urlencodeed,当时颇为不解,最终意识到,需要进行格式转换。
    通常有两种做法:

增加axiostransformRequest配置

axios({
    url: '/api',
    data: {
        firstName: 'Spawn',
        lastName: 'Heaston'
    },
    transformRequest: [function(data) {
        let ret = ''
        for (let i in data){
            ret += encodeURIComponent(i) + '=' + encodeURIComponent(data[i]) + '&'
        }
        return ret
    }]
})

使用qs包

import qs from 'qs'
qs.stringify(data)

这里其实还有很多有趣的写法:

var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
对浏览器要求高,但看caniuse上,现阶段基本上也可以使用了

axios 使用心得_第1张图片


鉴权

在项目中经常需要对用户身份进行鉴权,在Vue项目中通常需要axiosvue-router相结合使用,才能更好的把控权限。

Vue-router 官方推荐的写法是在路由的meta中设置字段(requiresAuth: true),但是具体情况具体分析,因为项目中页面较多,所以采取了匹配路由的形式

router.beforeEach((to, from, next) => {
  // 官方做法是meta,但该项目都是子路由,较多,采用模糊匹配
  if ((to.path.indexOf('/my/') !== -1) && !Storage.get('api_token')) {
    let url = to.fullPath.includes('/my/') ? '/my' : to.fullPath
    // 这里的处理不优雅,应该直接把currentUrl以get传参的形式传递给/signin
    // next(`/sign?redirect=${url}`)
    Storage.set('currentUrl', url)
    next('/signin')
  } else {
    next()
  }
})

这个是路由层面的拦截器,但是仅仅如此是不足以满足业务需求的,比如在商品详情页浏览的时候进行加入购物车操作,这时就需要对接口进行鉴权了。
这时可以有两种操作:

axios.interceptors.request.use(
    config => {
        // 在此处进行token校验
    }
)
axios.interceptors.reponse.use(
    res => {
          // 接口也会对用户进行鉴权,根据接口的response来进行处理
      if (res.data.login === '0') {
          let url = router.currentRoute.fullPath
          Storage.set('currentUrl', url)
          router.replace({
            path: '/signin'
          })
        }
        return res
    }
)

全局配置

上个项目中,只知道用config.js来进行baseURL配置,后来阅读文档才知道可以全局配置

axios.defaults.baseURL = '/apis'
axios.defaults.timeout = 5000

但是这个baseURL一般是为了在对接口进行proxy的时候使用,上线的时候其实很多时候并不需要进行配置

之前写过这样的代码

// 动态baseURL
const origin = window.location.origin
Storage.session.set('origin', origin)

// axios 默认配置
axios.defaults.baseURL = origin

其实部署上去之后,接口并不需要加域名,默认的就是当前域名,这块和后来接触的一个养老项目相比,理解就深刻了,因为接口部署在多个域名下,所以在SPA里就需要显式的把域名补全。

这样比较推荐的做法是,使用两个axios实例,然后对每个实例进行默认配置,比较灵活一些

let instance1 = axios.create({})
let instance2 = axios.create({})
instance1.defaults.baseURL = '/apis'
instance2.defaults.baseURL = '/jay'

all操作

因为项目中有的 数据并不是存放在一个接口中,如果采用

axios.get('/api1').then(res => {
    axios.get('/api2').then(r => {
        // 处理最终逻辑
    })
})

那么就耗时就是 api1 + api2 的时间了

所以axios也支持类似 Promise.all 操作

function get1 () {
    return axios.get('/api1')
}
function get2() {
    return axios.get('/api2')
}

axios.all([get1(), get2()]).then(axios.spread(function (acct, perms) {
    // Both requests are now complete
  })

你可能感兴趣的:(js)