REDUX SAGA - API 重试同构获取

问题描述

我正在尝试在以下上下文中添加重试逻辑 - 我进行 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,这不会发生:

enter image description here

解决方法

我担心的是文档说 - 如果 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 中的令牌进行比较,看看你是否有一个新的。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...