一、 抛出问题
1、当一个页面的请求过长时,点击了跳转路由到新的页面,但是上一个路由的请求结果在当前路由页面提示,非常难看且容易让客户混淆。(所以需要路由跳转取消上个路由页面的所有请求)
2、在当前页面某个请求长时间没拿到返回结果,然后用户又点击发起了相同请求,这时有可能后发送的请求返回的数据被先发送的请求覆盖,这样就得不到最新请求数据了。(所以需要取消当前路由页面的重复请求,以保证后发送的请求返回的数据不会被先发送的请求覆盖)
3、上面两种情况都会浪费网络资源
二、解决问题
1、我们在axios封装文件axios.js中写入如下代码:
import axios from 'axios';
import { message } from 'antd';
import qs from 'qs';
// 引入自己项目中的配置文件
import { hrefLogin } from 'src/configs';
// 响应时间
axios.defaults.timeout = 300000; // 5 min
axios.defaults.headers.post['Content-Type'] = 'application/json';
// 取消请求操作
const allPendingRequestsRecord = [];
const pending = {};
const removeAllPendingRequestsRecord = () => {
allPendingRequestsRecord && allPendingRequestsRecord.forEach((func) => {
// 取消请求(调用函数就是取消该请求)
func('路由跳转了取消所有请求');
});
// 移除所有记录
allPendingRequestsRecord.splice(0);
};
// 取消同一个重复的ajax请求
const removePending = (key, isRequest = false) => {
if (pending[key] && isRequest) {
pending[key]('取消重复请求');
}
delete pending[key];
};
// 取消所有请求的函数
export const getConfirmation = (mes = '', callback = () => {}) => {
removeAllPendingRequestsRecord();
callback();
};
// request interceptor
axios.interceptors.request.use(
(config) => {
// 在请求发送前执行一下取消操作,防止连续点击重复发送请求(例如连续点击2次按钮)
let reqData = '';
// 处理如url相同请求参数不同时上一个请求被屏蔽的情况
if (config.method === 'get') {
reqData = config.url + config.method + JSON.stringify(config.params);
} else {
reqData = config.url + config.method + JSON.stringify(config.data);
}
// 如果用户连续点击某个按钮会发起多个相同的请求,可以在这里进行拦截请求并取消上一个重复的请求
removePending(reqData, true);
// 设置请求的 cancelToken(设置后就能中途控制取消了)
config.cancelToken = new axios.CancelToken((c) => {
pending[reqData] = c;
allPendingRequestsRecord.push(c);
});
// application/x-www-form-urlencoded
if (config.resType === 'form') {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
config.data = qs.stringify(config.data);
return config;
}
return config;
},
(error) => Promise.reject(error),
);
// response interceptor
axios.interceptors.response.use(
(response) => {
if (response.status >= 400) {
// 没登录/过期/异常
if (response.status === 401) {
message.error('登录态过期,请重新登录');
// ...写入自己的代码逻辑
return;
}
message.error('网络连接异常');
return Promise.reject(response);
}
return response;
},
(error) => {
// 终结由于取消重复请求而引发的报错提示
if (axios.isCancel(error)) {
return new Promise(() => {});
}
if (error.response) {
if (error.response.status === 401) {
message.error('登录态过期,请重新登录');
// ...写入自己的代码逻辑
} else if (error.response.status === 403) {
message.error('您尚无权限访问');
// ...写入自己的代码逻辑
} else if (error.response.status === 511) {
message.error('您尚未登录,请登录');
// ...写入自己的代码逻辑
} else {
message.error('网络连接异常');
}
}
return Promise.reject(error);
},
);
export default axios;
2、在React路由跳转时取消上个页面的所有请求
这里是自己封装的react路由文件router.js。
import React, { Suspense } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
// 引入上面封装的axios文件中的getConfirmation函数
import { getConfirmation } from 'src/tools/axios';
import { Loading } from 'src/components';
const SubRoutes = (route) => (route.tag === 'Redirect' ? (
<Redirect
from={route.from}
to={route.to}
exact={route.exact}
render={(props) => (
<route.component {...props} routes={route.children} />
)}
/>
) : (
<Route
path={route.path}
exact={route.exact}
render={(props) => {
// 路由跳转取消上个组件所有的pending请求
getConfirmation();
return (
<route.component {...props} routes={route.children} />
);
}}
/>
));
const Routes = (props) => (
<Suspense fallback={<Loading />}>
<Switch>
{props.routes.map((route) => (
<SubRoutes key={JSON.stringify(route)} {...route} />
))}
</Switch>
</Suspense>
);
export { Routes };
三、App.js中使用路由
import React, { useEffect } from 'react';
import { HashRouter as Router } from 'react-router-dom';
import { message } from 'antd';
// 引入上面封装的路由文件
import { Routes } from 'src/router';
// 路由组件路径配置
import allRouters from 'src/data/allRouters';
// antd message 全局配置
message.config({
maxCount: 1,
});
const App = () => {
return (
<Router>
<div className="App">
<Routes routes={allRouters} />
</div>
</Router>
);
};
export default App;
版权声明:本文为m0_38134431原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。