最近遇到了一个场景,前端发送请求都是直接发送,但如果是报错了402(用户的登陆过期)就需要发送一个refresh接口,刷新用户的登陆信息。
目标是用户信息过期后,也可以通过refresh接口无感续登陆的效果
如此需要创造力的场景,就需要思考以下几点了:
1.接口大概200多个,应该是写一个统一的函数进行预处理,而不是每一个单独改造,也不能触碰业务代码
2.预处理后,如果接口正常(状态码200)就正常返回结果。如果不正常,就执行refresh流程,之后再重新请求一次,返回第二次的请求结果
3.“正常返回”指的是需要返回到对应接口函数的.then中,就和普通调接口一样,不需要再额外处理,改造最小
对于这样的异步请求,那么我们会考虑到使用promise进行包裹,在请求结束后将结果resolve回去,首先定义promise函数:
function newRequest(url: string, option: any) {
return new Promise((resolve, reject) => {
try {
//执行函数并查看状态码
} catch (error) {
// 处理promise函数本身的异常
console.error(error);
resolve('服务异常')
}
});
}
之后,我们在try中正常执行我们的接口。这里使用umi-request举例,可以随意替换为其他request包,比如axios:
import request from 'umi-request';
function newRequest(url: string, option: any) {
return new Promise(async (resolve, reject) => {
try {
//通过async和await快速获取到接口返回
const result: any = await request(url, option)
} catch (error) {
// 处理B函数的异常
console.error(error);
resolve('服务异常')
}
});
}
之后我们判断result,如果返回值为402,就执行refresh,如果没有,就正常结算:
import request from 'umi-request';
function newRequest(url: string, option: any) {
return new Promise(async (resolve, reject) => {
try {
//通过async和await快速获取到接口返回
const result: any = await request(url, option)
if (result?.status==='402') {
// 开始尝试refreshLogin
/**
* 刷新token,下为范例
* 需要自己定义自己的refresh函数
*/
request(`${prefix}/loginrefresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*',
},
}).then(async (res: any) => {
if (res) {
//开始将新的用户信息保存在localstorage中,也可以执行其他操作
window.localStorage.setItem('userInfo', JSON.stringify(res))
//之后,再次执行当前服务,并返回
const response = await request(url, option)
resolve(response)
} else {
//refresh不成功的执行,比如让用户返回登录页
}
})
} else {
//如果请求正常,就正常返回结果
resolve(result)
}
} catch (error) {
// 处理B函数的异常
console.error(error);
resolve('服务异常')
}
});
}
这样,就算写完了
按照常规的request使用方法使用即可:
//newRequest函数和普通的request、axios函数使用方法完全一致
export function getList(data: any) {
return newRequest
(`${SERVER}/list`, {
method: 'POST',
data
});
}
最终效果如下,在服务挂掉后会尝试刷新token,之后再次自动请求服务
如此,我们可以做到无感刷新用户信息,而不需要用户重新登陆,当前被拦截的402请求也可以自动重新请求一次并正常返回