在做vue、react项目的时候常会用axios请求库来与后端进行数据交互。我们通常采用一个用户凭证token来验证用户身份,服务器根据token进行判断当前用户是否有权限调用接口。
经常遇到的一个问题是,调用接口时token可能已经过期,此时调用接口会失败,需要重新登录后再调用接口。通常我们可能处理为,用户走完登录流程后再重新手动触发一次请求。这样的实现本身没什么问题,但是给用户的操作体验上有被中断的感觉,今天尝试解决了一下这个问题。
我的业务场景是,当一个接口(比如”用户发表评论“)返回token过期或者未验证的状态码时,调出登录弹窗,登录成功后再次发送评论请求。当然我们可以在评论接口处对状态码进行判断,token失效则重新发送请求;如果有其它接口也类似处理。这个方法最大的问题在于对于每个接口都要单独处理,然而程序员最大的优点就是——懒。这个方法虽然可行,对于一个懒人来说并不怎么好用,那更好的办法的是什么呢?
axios请求拦截器本身可以获取请求的地址、参数、超时时间等配置,请求的重发变得很简单;同时axios库的请求返回为一个promise对象,得益于Promise强大的嵌套异步处理,可以使得请求接口调用对请求重发“无感”——即调用接口的时候你可以默认它一定成功,因为失败的情况在拦截器已经重发了。
function getToken () {
return localStorage.getItem('token')
}
function clearToken () {
localStorage.removeItem('token')
}
function setToken (token) {
localStorage.setItem('token', token)
}
function login () {
// 登录处理代码
}
const instance = axios.create({
baseURL: 'http://xxxx', // 请求域名前缀
timeout: 10 * 1000
})
const requestError = error => Promise.reject(error)
const beforeRequest = config => {
config.headers['token'] = getToken() || undefined
return config
}
const beforeResponse = res => () => {
if (res.data.code == 401) { // 401错误表示未登录授权或者token失效
clearToken()
return login().then(() => {
return instance.request(res.config) // 这里是核心代码,登录成功后重新请求!返回Promise对象。
})
}
return res
}
instance.interceptors.request.use(beforeRequest, requestError)
instance.interceptors.response.use(beforeResponse, requestError)
上述代码里重新请求部分调用了login函数(login().then(callback)),login函数体空置了,接下来将讨论其实现。login预期返回一个Proimise,登录成功则Promise.then注册的回调函数将被调用。
我们可以将登录弹窗封装为一个组件,然后通过手动挂载组件来函数式地调用登录流程。可以在登录组件内部提供一个函数以供外部login函数调用,比如showModal,该函数直接返回一个Promise,login函数只要调用该函数并直接返回即可。
登录组件Login.vue封装:
<template>
<div v-show="show">
<!-- 登录框 -->
</div>
</template>
<script>
export default {
data () {
return {
username: '',
password: '',
resolve: null,
reject: null,
show: false
}
},
methods: {
showModal () {
return new Promise((resolve, rejcet) => {
this.show = true
this.resolve = resolve
this.reject = reject
})
},
hideModal () {
this.show = false
this.reject = null
this.resolve = null
this.username = ''
this.password = ''
},
success () {
this.hideModal()
this.resolve && this.resolve()
},
fail () {
this.hideModal()
this.reject && this.reject()
}
}
}
</script>
封装好了Login.vue组件,接下来实现login函数:
import Login from '@/components/Login.vue'
import Vue from 'vue'
// ...
let vm = null
function login() {
if (!vm) {
const LoginConstructor = Vue.extend(Login)
vm = new LoginConstructor().$mount()
}
return vm.showModal()
}
// ...
login函数闭包了一个外部变量vm,目的是通过vm引用已创建的Login组件实例,避免重复创建(即“单例”)。这样,完整的登录后重发请求流程即完成了。
一般而言只要谈到异步,通常提到回调函数。JS里的Promise是一个强大的回调函数管理器。本文的实现方案正是利用了Promise的特性,在接口无权限时,将“登录+重新请求”的过程封装为Promise并返回,实现接口调用过程中无权限登录统一处理。这样在接口调用的地方,可以不用单独处理无权限的情况,一定程度上避免用户操作被登录流程打断。
来自:https://wintc.top/article/53
axios的功能特性:在浏览器中发送 XMLHttpRequests 请求,在 node.js 中发送 http请求,支持 Promise API,拦截请求和响应,转换请求和响应数据,自动转换 JSON 数据,客户端支持保护安全免受 XSRF 攻击
axios基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用。项目中发现,在安卓4.3及以下的手机不支持axios的使用,主要就是无法使用promise。加上以下polyfill就可以了。
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。axios中get/post/put/patch请求。传参格式为 formData ,传参格式为 query 形式 ,传参格式为 raw等
axios-mock-adapter可以用来拦截http请求,并模拟响应,使用起来也很简单,比如你想模拟下服务器返回个500错误,什么404找不到、403禁止访问、500服务器错误、503服务不可用、504网关超时等等,你都能模拟出来
分享下我自己的axios封装,axios是个很好用的插件,都是一些params对象,所以很方便做一些统一处理。当然首先是npm安装axios 很简单。在src下新建文件夹 service / index.js,接着上代码
最近做项目遇到一款浏览器,由于缓存了get请求,导致不管如何刷新,数据都不更新的问题。以下分享一下解决办法:解决思路就是给每一条get请求增加一个timestamp的参数,value为时间戳
发送请求模块目录,@/api/url中存放的是每个模块的URL,使用webpack提供的require.context将src/api/url下后缀为js的所有文件引入,并整理出一个对象。整合common.js & product.js,最终得到的对象如下:
axios的二次封装,功能实现:1.兼容ie浏览器避免缓存2.减少或更新重复请求3.接口域名使用环境变量4.全局loading状态5.可关闭的全局错误提醒6.可开启携带全局分页参数
在vue项目开发过程中,为了方便在各个组件中调用axios,我们通常会在入口文件将axios挂载到vue原型身上,如下:这样的话,我们在各个组件中进行请求时
项目中需要验证登录用户身份是否过期,是否有权限进行操作,所以需要根据后台返回不同的状态码进行判断。axios的拦截器分为请求拦截器和响应拦截器两种。我一般把拦截器写在main.js里。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!