问题描述
我正在尝试在以下上下文中添加重试逻辑 - 我进行 API 调用 -> 响应为 401 -> 我调用 APi 在后台请求新令牌。我的 API 调用不应该失败。以下是我的 API 文件(这很常见 - 我的应用程序中的每个 API 都调用此文件来进行 FETCH)
注意:我看过使用 fetch().then() 方法的文章,但我们使用的是 YIELD。
特定的 API 文件 -
// apiRequest = 我在下面指定的 api.js 文件的一部分
const response = yield retry(3,1000,apiRequest,options); // My apiRequest while trying for getting new access tokens send me a NULL,do we want that ?
if (undefined !== response && null !== response) {
const formattedResponse = yield apply(response,response.json);
if (response.status === 200) {
yield call(handleAddCampaignResponseSuccess,formattedResponse);
} else {
yield call(handleAddCampaignResponseFailure,formattedResponse);
}
} else{
// Show some Message on UI or redirect to logout
}
// api.js
function* apiRequest(options) {
const { method,body,url } = options;
const accessToken = yield select(selectors.AccessToken);
const idToken = yield select(selectors.IdToken);
try {
var response = yield call(fetch,url,{
method: method,body: body,headers: {
"Content-Type": ContentTypes.JSON,Authorization:
accessToken != "" ? `Bearer ${accessToken} ${idToken}` : "",},});
if (null !== response) {
if (response.status === HTTP_CODES.HTTP_UNAUTHORIZED) {
// Unauthorized requests - redirect to LOGOUT
// Request for Refresh Token !
yield put(refreshTokenOnExpiry());
return null; // Is this necessary
} else if (response.status === HTTP_CODES.HTTP_NOT_FOUND) {
return null;
} else if (response.status === HTTP_CODES.HTTP_SERVER_ERROR) {
// Logout cos of serrver error
yield put(handleLogout());
return null;
} else {
console.log("From Else part");
// - Called on intent to ensure we have RESET redirections and that it does not cause issues of redirection.
yield put(resetRedirections());
return response;
}
} else {
// Handle Logout
yield put(stopTransition());
yield put(handleLogout());
}
} catch (error) {
// Cors Error in case of DEV URL
// See if SAGA is Still listening to the Action Dispatches
console.log("From CATCH BLOCK");
yield put(stopTransition());
yield put(handleLogout());
return null;
}
}
我担心的是文档说 - 如果 API 请求失败,那么它会重试,我不明白它的意思。这是否意味着 API 返回 NULL 或 Http 200 以外的任何内容?因为我希望 API 在出现 401 时重试
API.JS 是我网站上所有 API 调用的文件。另外,我如何确保 refreshTokenOnExpiry 只被调用一次(意味着一次将有多个 API 调用,每个调用 401 时最终都会调用 refreshTokenOnExpiry 这个 API )
我是生成器函数的新手,所以我确定我一定是在某个地方搞砸了。
此外,如果有人可以帮助我正确构建此代码,那将是非常有帮助的。谢谢!
添加图像以供参考 - 我希望重试失败的 API,这不会发生:
解决方法
我担心的是文档说 - 如果 API 请求失败,那么它会重试,我不明白它的意思。这是否意味着 API 返回 NULL 或 Http 200 以外的任何内容?因为我希望 API 在出现 401 时重试
向下滚动到 redux-saga recipes 中的“重试 XHR 调用”部分,了解 retry
效果在幕后做了什么。
retry
效果可用于任何函数,而不仅仅是 API 调用,因此它不会查看响应代码。它将“失败”定义为引发错误而不是完成执行的代码。所以你需要做的是throw
你的错误apiRequest
。
不能保证,但试试这个:
if (response.status === HTTP_CODES.HTTP_UNAUTHORIZED) {
// Unauthorized requests - redirect to LOGOUT
// Request for Refresh Token !
yield put(refreshTokenOnExpiry());
throw new Error("invalid token");
}
您需要弄清楚如何确保在重试之前设置新令牌。您可能希望构建自己的操作链,而不是依赖于 retry
。例如,您可以 put
类型为“RETRY_WITH_NEW_TOKEN”的操作具有包含原始 options
和尝试使用的令牌的有效负载。这样你就可以将它与 state 中的令牌进行比较,看看你是否有一个新的。