未捕获(在承诺中)TypeError:在axios中刷新令牌时无法读取未定义的属性(读取'then')
2023-04-22
459
我想在 axios
"axios": "^1.3.4",
中后台刷新 token,当服务端返回的 access token 过期后,客户端将请求存储在队列中,并在新的 token 刷新后恢复请求。当我在 react 中使用 promise 时,如下所示:
instance.interceptors.response.use((response:AxiosResponse<any, any>) => {
const originalRequest:InternalAxiosRequestConfig<any> = response.config;
if(isRefreshing){
addRequestToQueue(originalRequest);
}
if (!isRefreshing) {
if(response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED){
addRequestToQueue(originalRequest);
isRefreshing = true;
// refresh the access token
ResponseHandler.handleWebCommonFailure(response.data)
.then((data:any) => {
isRefreshing = false;
pendingRequestsQueue.forEach((request) => {
const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
request.resolve(accessToken)
.then((resp:any)=>{
// get the action of original request
const action = request.action;
const data = resp.data.result;
// change the state to make it render the UI
store.dispatch(action(data));
});
});
pendingRequestsQueue = [];
});
}
}
return response;
},
(error: any) => { return Promise.reject(error) }
)
此行
request.resolve(accessToken)
显示错误
caught (in promise) TypeError: Cannot read properties of undefined (reading 'then')
,这是
addRequestToQueue
函数定义:
function addRequestToQueue(originalRequest: any){
return new Promise((resolve, reject) => {
pendingRequestsQueue.push({ resolve, reject });
})
.then((data:any) => {
originalRequest.headers['x-access-token'] = data.accessToken;
originalRequest.headers['x-request-id'] = uuid();
return instance(originalRequest);
})
.catch((err) => {
return Promise.reject(err);
});
}
我应该怎么做才能解决这个问题?这是我的 axios 客户端的完整代码:
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { v4 as uuid } from 'uuid';
import store from '../store/store';
import { ResponseCode, ResponseHandler, WheelGlobal } from 'js-wheel';
let isRefreshing = false
let pendingRequestsQueue: Array<any> = [];
const instance = axios.create({
timeout: 60000
})
instance.defaults.headers.post['Content-Type'] = 'application/json'
instance.interceptors.request.use((request) => {
const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
accessToken && (request.headers['x-access-token'] = accessToken);
request.headers['x-request-id'] = uuid();
return request
},
(error: any) => {
return Promise.reject(error)
}
)
function addRequestToQueue(originalRequest: any): Promise<any> {
return new Promise((resolve, reject) => {
pendingRequestsQueue.push({ resolve, reject });
})
.then((data: any) => {
originalRequest.headers['x-access-token'] = data.accessToken;
originalRequest.headers['x-request-id'] = uuid();
return instance(originalRequest);
})
.catch((err) => {
return Promise.reject(err);
});
}
instance.interceptors.response.use((response: AxiosResponse<any, any>) => {
const originalRequest: InternalAxiosRequestConfig<any> = response.config;
if (isRefreshing) {
addRequestToQueue(originalRequest);
}
if (!isRefreshing) {
if (response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED) {
addRequestToQueue(originalRequest);
isRefreshing = true;
// refresh the access token
ResponseHandler.handleWebCommonFailure(response.data)
.then((data: any) => {
isRefreshing = false;
pendingRequestsQueue.forEach((request) => {
const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
const promise = request.resolve(accessToken);
if (promise) {
promise.then((resp: any) => {
// get the action of original request
const action = request.action;
const data = resp.data.result;
// change the state to make it render the UI
store.dispatch(action(data));
});
}
});
pendingRequestsQueue = [];
});
}
}
return response;
},
(error: any) => { return Promise.reject(error) }
)
export function requestWithAction(config: any, action: (arg0: any) => any) {
return instance(config).then(
(response: { data: { result: any; }; }) => {
const data = response.data.result;
store.dispatch(action(data));
return response.data;
}
).catch(
(error: any) => {
console.error(error);
}
);
}
2个回答
问题是
resolve
不返回承诺。它返回
undefined
。
退一步说,您不需要像
addRequestToQueue
这样的函数来创建新的承诺并将其
resolve
函数推送到队列中。当您已经有要使用的诺言 (
instance()
) 时创建
new Promise
是一种反模式。
相反,将请求放入队列并在主函数中调用 axios (
instance
),您可以在其上链接
then
调用。像这样:
instance.interceptors.response.use((response:AxiosResponse<any, any>) => {
const originalRequest:InternalAxiosRequestConfig<any> = response.config;
if(isRefreshing){
pendingRequestsQueue.push(originalRequest); // <--
}
if (!isRefreshing) {
if(response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED){
pendingRequestsQueue.push(originalRequest); // <--
isRefreshing = true;
// refresh the access token
ResponseHandler.handleWebCommonFailure(response.data)
.then((data:any) => {
isRefreshing = false;
pendingRequestsQueue.forEach((request) => {
const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
// Moved code from `addRequestsToQueue` here:
request.headers['x-access-token'] = accessToken;
request.headers['x-request-id'] = uuid();
instance(request) // This returns a promise (contrary to `resolve`)
.then((resp:any)=>{
// get the action of original request
const action = request.action;
const data = resp.data.result;
// change the state to make it render the UI
store.dispatch(action(data));
});
});
pendingRequestsQueue = [];
});
}
}
return response;
},
(error: any) => { return Promise.reject(error) }
)
trincot
2023-04-22
您可以在句点“.”前使用“?”,并在代码中使用
typeof "something" !== "undefined"
,您可以执行
request?.resolve(accessToken)
sina soleymanzadeh
2023-04-22