Javascript Axios:如何在请求拦截器中正确取消请求?
如果没有令牌,我想取消请求,因此我喜欢这样做:Javascript Axios:如何在请求拦截器中正确取消请求?,javascript,axios,Javascript,Axios,如果没有令牌,我想取消请求,因此我喜欢这样做: instance.interceptors.request.use(配置=>{ 如果(!getToken()){ log(“拦截器:无访问令牌”); }否则{ config.headers.Authorization=“Bearer”+getToken().accessToken; 返回配置; } }); 但是在负面场景中会出现一个错误TypeError:无法读取未定义的属性“cancelToken”您不能在拦截器内使用该令牌,而是抛出Cance
instance.interceptors.request.use(配置=>{
如果(!getToken()){
log(“拦截器:无访问令牌”);
}否则{
config.headers.Authorization=“Bearer”+getToken().accessToken;
返回配置;
}
});
但是在负面场景中会出现一个错误
TypeError:无法读取未定义的属性“cancelToken”
您不能在拦截器内使用该令牌,而是抛出Cancel
axios.interceptors.response.use(function (response) {
throw new axios.Cancel('Operation canceled by the user.');
}, function (error) {
return Promise.reject(error);
});
请参阅本帖:
以下是解决方案
import axios from 'axios';
const CancelToken = axios.CancelToken;
let cancel;
axios.interceptors.request.use((config) => {
if (cancel) {
cancel(); // cancel request
}
config.cancelToken = new CancelToken(function executor(c)
{
cancel = c;
})
return config
}, function (error) {
return Promise.reject(error)
});
我是这样实施的。我不确定这是否是最好的解决方案,但对于我的用例来说是有用的。 我的想法是不要取消最后一个请求。我想取消以前对同一个端点的请求,让最后一个完成他的工作。因此,我会跟踪正在执行的请求
// I keep track of the current requests that are being executed
const currentExecutingRequests = {};
axios.interceptors.request.use(
(req) => {
let originalRequest = req;
if (currentExecutingRequests[req.url]) {
const source = currentExecutingRequests[req.url];
delete currentExecutingRequests[req.url];
source.cancel();
}
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
originalRequest.cancelToken = source.token;
currentExecutingRequests[req.url] = source;
// here you could add the authorization header to the request
return originalRequest;
},
(err) => {
return Promise.reject(err);
}
);
axios.interceptors.response.use(
(response) => {
if (currentExecutingRequests[response.request.responseURL]) {
// here you clean the request
delete currentExecutingRequests[response.request.responseURL];
}
return response;
},
(error) => {
const { config, response } = error;
const originalRequest = config;
if (axios.isCancel(error)) {
// here you check if this is a cancelled request to drop it silently (without error)
return new Promise(() => {});
}
if (currentExecutingRequests[originalRequest.url]) {
// here you clean the request
delete currentExecutingRequests[originalRequest.url];
}
// here you could check expired token and refresh it if necessary
return Promise.reject(error);
}
);
我的解决方案基于
axios.ts
const axiosInstance = axios.create({ baseURL: apiBaseUrl });
axiosInstance.interceptors.request.use(
req => {
const originalRequest = req;
const cancelUniqId = (originalRequest.cancelToken as unknown) as string;
if (Object.hasOwnProperty.call(currentExecutingRequests, cancelUniqId)) {
const source = currentExecutingRequests[cancelUniqId];
delete currentExecutingRequests[cancelUniqId];
source.cancel();
}
if (cancelUniqId) {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
originalRequest.cancelToken = source.token;
currentExecutingRequests[cancelUniqId] = source;
}
return originalRequest;
},
err => {
return Promise.reject(err);
}
);
axiosInstance.interceptors.response.use(
response => {
for (const key of Object.keys(currentExecutingRequests)) {
if (currentExecutingRequests[key].token === response.config.cancelToken) {
delete currentExecutingRequests[key];
break;
}
}
return response;
},
error => {
const { response } = error;
if (axios.isCancel(error)) {
return new Promise(() => {
//
});
}
for (const key of Object.keys(currentExecutingRequests)) {
if (currentExecutingRequests[key].token === response.config.cancelToken) {
delete currentExecutingRequests[key];
break;
}
}
return Promise.reject(error);
}
);
export { axiosInstance };
用法:
axiosInstance.request({
url: "some/req/path",
method: "POST",
params: {...},
data: {...},
cancelToken: "someUniqRequestID" // <-- IMPORTANT!
})
axiostation.request({
url:“some/req/path”,
方法:“张贴”,
参数:{…},
数据:{…},
cancelToken:“someUniqRequestID”//对于后来的谷歌来说,这是一个从
这与提议的内容基本相同,但形式更为简洁。@的回答完美地解决了这一问题,但添加了一行:
const CancelToken=Axios.CancelToken;
然后,事情会是这样的:
instance.interceptors.request.use(配置=>{
/*一些逻辑*/
const CancelToken=Axios.CancelToken;
返回{
…配置,
cancelToken:new cancelToken((cancel)=>cancel('cancel repeated request'))
};
});
它是否会导致函数(错误){…}
代码分支运行或仅在稍后落入.catch()
中?我猜您的意思是,当您抛出axios.Cancel()
时,代码将流向何处。我已经尝试过这一点,取消将在catch()中显示为错误
稍后直接执行。这在编写时是不正确的(您不能在拦截器中使用cancel令牌),并且不能处理所有用例,例如,如果请求已经启动,您现在需要取消所有请求(例如,由于会话到期,用户已注销)。关于这一点,请参阅vijay的解决方案。OP要求在请求截获中提供解决方案。我认为这是关于取消已运行的请求,OP谈论的是一个尚未启动的请求。什么是“让取消”
?以及为什么您要检查它是否正确,然后再调用它!我很困惑。您还可以演示如何在useffect中清理已取消的请求吗你的意思是这样的吗?React.useffect(()=>{const CancelToken=axios.CancelToken;const source=CancelToken.source();(async()=>{try{const response=wait axios.get(URL,{CancelToken:source.token});console.log(response);}catch(e){console.log(e);}}}();return()=>source.cancel();},[]);
您可以在这里查看它以了解更多说明:
instance.interceptors.request.use(config => {
/* some logic */
return {
...config,
cancelToken: new CancelToken((cancel) => cancel('Cancel repeated request'))
};
});