
之前做过的项目在处理请求的
401
状态码的时候,没有特殊要求的话,大部分处理是给用户一个提示“登录已超时”,然后跳转到登录页面。
这种情况下,其实对于刚刚报错401的那个请求,是没有成功的。需要用户重新进入到刚刚的操作步骤,并且重复他的上一次操作步骤

鉴于我们的平台中,某些环节存在较长的操作流程,整个步骤也较为繁琐和关联很多细节;于是考虑,做一个登录失效的拦截弹窗,达到重连,并且不中断原来的操作的效果。
📌设计思路
- 在axios的
response.status = 401
处拦截 - 弹窗中需要提示用户登录超时,需要填写登录密码,重新登录
- 登录校验成功之后,重新启动刚才401失败的那个http请求,因要求记住失败时的请求参数。
🧙具体实现
实现方式是封装成一个重连验证组件Identification
我们需要通过,组件内的登录的这个异步操作的结果【是 or 否】,决定“是否重连”,因此可以使用
promise
;
在组件内部,登录成功才会执行resolve
回调。从弹出弹框到输入密码,到点击登录,这个操作也是异步的,所以在组件内部,可以通过eventEmitter
进行通信,触发执行这个resolve
回调。
组件需要暴露出两个api:
- showModal
- 创建模态框,里面包括表单项、确认按钮,用于用户填写登录密码
- 用
eventEmitter
.on
注册登录后的成功回调resolveCallback
,const ee = new EventEmitter();
showModal: () => {
return new Promise((resolve) => {
// 注册回调方法
ee.on('resolveCallback', (code) => {
resolve(code);
});
const loginModalDom = document.getElementById('__login_modal');
// 只弹出1个登录框
if (!loginModalDom) {
const div = document.createElement('div');
div.id = '__login_modal';
document.body.appendChild(div);
ReactDOM.render(
<LoginModal visible={true} onCancel={identification.removeModal} />,
div,
);
}
});
}
- removeModal
移除模态框
const identification = {
...showModal,
removeModal: () => {
const loginModalDom = document.getElementById('__login_modal');
if (loginModalDom) {
loginModalDom.remove();
}
ee.emit('resolveCallback', 0);//回调
},
};
export default identification
🎇登录模态框
//FormModal
<Modal
title="请重新登录"
visible={visible}
//...
>
<div style={{ padding: '24px' }}>
<Form
//...
onFinish={onFinish}
>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入密码' }]}
>
<Input.Password />
</Form.Item>
<Form.Item>
<Button htmlType="submit" type="primary" block>登录</Button>
</Form.Item>
</Form>
</div>
</Modal>
//LoginModal
const [form] = Form.useForm();
const { visible = false, onCancel } = props;
const [errorText, setErrorText] = useState('');
async function onFinish(values: any) {
const res = await login({
data: values,
errorHandler: (e) => {
setErrorText(e.message);
},
});
const { code, data } = res;
if (code === 0) {
//...
ee.emit('resolveCallback', 1); //回调
}
}
return (<FormModal/>);
🧪使用
//在axios的状态码401断言下,处理操作
case(status === 401) :
//...
const callbackCode = await identification.showModal();
if (callbackCode === 1) {
identification.removeModal();
// 登录成功后,重发之前失败的请求
//这里的option是直接在axios封装体中,直接可以拿到的
const res = await request(option);
return Promise.resolve(res);
} else {
//...处理相关的异常逻辑
return Promise.resolve({
code: error?.response?.status || defaultErrorCode,
data: null,
error: errorText,
});
}
📎参考
查看源代码逻辑,根据业务在代码中包括一些状态管理的操作,可以忽视💦

网友评论