从刚开始接触 Vue
时,官方维护了一个 request
项目是 vue-resource
,后来推荐使用社区的 axios
来作为 request
工具。
两者之间的区别:
axios
支持服务端(Node
中自带的 request
包并不支持promise
,通常需要使用bluebird
来进行promise
化),resource
不支持服务端axios
功能更加丰富,支持 Intercept
功能。刚开始使用axios
的时候,只会在 main.js
中统一配置
Vue.prototype.$http = axios
然后就按照之前Vue-resource
的写法进行书写,在小项目中这样使用也确实没有提现出axios
的优势。
在17年11月进行的创天下项目中,遇到了很多关于 权限校验 及一些数据格式转化的问题。
axios
默认的是以 JSON
数据格式来传输的。
而常见的POST
提交数据的格式有四种,分别是:
text/xml
而创天下项目中使用的基本都是application/x-www-urlencodeed
,当时颇为不解,最终意识到,需要进行格式转换。
通常有两种做法:
增加axios
的transformRequest
配置
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上,现阶段基本上也可以使用了
在项目中经常需要对用户身份进行鉴权,在Vue项目中通常需要axios
和vue-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'
因为项目中有的 数据并不是存放在一个接口中,如果采用
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
})