目前有这样一个需求:前端对需要验证的接口进行拦截并在弹框中获取验证码,在输入验证码并验证成功后,自动带着验证码重新请求需要验证码验证的接口。
分析
- 重新自动触发请求,需要在axois拦截器中设置满足条件就重新执行对应的请求的功能
// 响应拦截器中
if (error.response.data.code == '0510' || error.response.data.code == '0511') {
const config = error.config
// 处理逻辑
return Promise.reject(error)
}
- 需要验证的接口可能会有很多,同时请求的接口也可能会有很多,需要一个待重新请求接口的数组
if (error.response.data.code == '0510' || error.response.data.code == '0511') {
const config = error.config
// 多个需要验证的接口时,只弹一个输入验证码框
if (waitReq.length == 0) {
// 展示验证码弹框
verifycode(error.response.data.CaptchaType)
}
waitReq.push(config) // 其他需要验证的接口,暂存数组等待验证成功后再次重新请求
return Promise.reject(error)
}
- 拦截器中需要弹框组件的展示,并将输入的验证码存储,验证成功后执行需要验证的接口请求
async sureVerify() {
let resource_captcha = this.uuid + '_' + this.verify
store.commit('updateVerifyCode', resource_captcha) // 验证码存储
try {
await getCaptchaCodeCheck({captchaKey:this.uuid, captcha: this.verify})
this.success() // 验证成功回调中添加成功播报 $emit 事件
} catch (error) {
this.getMsgCodeFu() // 重新获取验证码
}
},
- 接口重新请求成功后,需要关闭弹框,清空数组
vm.$on('success', async (resolve) => {
await Promise.allSettled(waitReq.map(config => service(config)))
vm.hideModal() // 关闭验证弹框
waitReq = []
resolve()
})
完整代码
弹框组件
<el-form inline>
<el-row>
<el-col :span="10">
<el-form-item>
<el-input v-model="verify" placeholder="请输入验证码"></el-input>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item>
<img :src="verifyImage" alt="" @click="getMsgCodeFu">
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item>
<el-button type="primary" @click="sureVerify">确认</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
import store from '@/store'
import { getMsgCode, getCaptchaCodeCheck } from '@/api/index.js'
export default {
data() {
return {
isDialogVisible: false,
uuid: this.UUID(20), // 随机数
verifyImage: '',
verify: '',
resolve: null,
reject: null
}
},
methods: {
// 确认按钮
async sureVerify() {
let resource_captcha = this.uuid + '_' + this.verify
store.commit('updateVerifyCode', resource_captcha)
try {
await getCaptchaCodeCheck({captchaKey:this.uuid, captcha: this.verify})
this.success()
} catch (error) {
this.getMsgCodeFu()
}
},
// 获取验证码
getMsgCodeFu() {
const _data = { captchaKey: this.uuid, captchaType: 1 }
getMsgCode(_data)
.then((response) => {
this.verifyImage = response.data
this.isDialogVisible = true
})
.catch((err) => {})
},
// 展示弹框
showModal() {
return new Promise((resolve, rejcet) => {
this.getMsgCodeFu() // 获取验证码
this.resolve = resolve
this.reject = rejcet
})
},
// 关闭弹框
hideModal() {
Object.assign(this.$data, this.$options.data())
},
// 成功回调
success() {
this.$emit('success', this.resolve)
}
}
}
axios 拦截器中代码如下:
import axios from 'axios'
import Vue from "vue";
import VerifyCode from '@/components/verifyCode'
import store from '@/store'
let vm = null
let waitReq = [];//等待请求列表
function verifycode (captchaType) {
if (!vm) {
// 挂载组件
const VerifyConstructor = Vue.extend(VerifyCode)
vm = new VerifyConstructor().$mount()
// 监听验证成功事件
vm.$on('success', async (resolve) => {
// 循环并行执行独立的异步接口(需要验证的)
await Promise.allSettled(waitReq.map(config => service(config)))
vm.hideModal() // 关闭验证弹框
waitReq = []
resolve() // 放行
})
}
return vm.showModal(captchaType)
}
// 创建一个axios实例
const service = axios.create({
baseURL: '/',
})
// 请求拦截器
service.interceptors.request.use(
config => {
try {
// 请求头中添加已存储的验证码,后台需要验证的接口需要该参数
config.headers['resource_captcha'] = store.state.verifyCode
} catch (error) { }
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
if (response.data.code != 200 ) {
return Promise.reject(new Error(response.data.msg || '服务器异常'))
}else {
return res
}
},
error => {
if (error.response) {
if (error.response.data && error.response.data.code) {
// 需要验证的接口
if (error.response.data.code == '0510' || error.response.data.code == '0511') {
const config = error.config
// 多个需要验证的接口时,只弹一个输入验证码框
if (waitReq.length == 0) {
verifycode(error.response.data.CaptchaType)
}
waitReq.push(config) // 暂存数组等待验证成功后再次重新请求
return Promise.reject(error)
} else {
return Promise.reject(error)
}
} else {
return Promise.reject(error)
}
}
}
)
export default service