RXJS可观察物:在其他异步请求后重试



我的用例是:

  1. 用户请求从我们的API中请求资产,该资产由于JWT到期而失败(以HTTPONLY cookie传递)-API返回401状态代码。
  2. 我们使用refresh_token再次对其进行身份验证(不做任何事情)
  3. 我们将新的JWT发送到我们的API,以将其设置为Httponly cookie,以替换已过期的cookie。
  4. 然后,我们想在步骤1中重试用户对API的原始请求。

我正在尝试在我的Redux应用程序中使用Redux-Observable使用可观察到的物品。如果您能想到另一种使上述用户流程工作的方式,我很乐意听到。

nb。我正在使用rxjs V5

export const fetchAssetListEpic = (action$, store) => {
  return action$.ofType('FETCH_ASSET_LIST')
  .switchMap( action => {
    const options = {
      crossDomain: true,
      withCredentials: true,
      url: uriGenerator('assetList', action.payload)
    };
    return ajax(options);
  })
  .map(fetchAssetListSuccess)
  .retryWhen(handleError)
  .catch(redirectToSignIn);
};
function handleError(err) {
  return (err.status === 401) ? 
  /* Authenticate here [Step 2] */
  /* Send new JWT to API [Step 3] */
  /* If successful make original request again [Step 4] */
  :
  Observable.throw(err);
}
  
function redirectToSignIn() {
  /*I will redirect here*/
}

到目前为止,我能够完成步骤1、2和3,但不太确定添加步骤4的方法。

您可能不想做的一件事就是允许错误进入顶级流。即使您进行catch,您也有效地杀死了顶级流。因此,除非您的重定向是通过诸如React-Router之类的诸如React-Router之类的柔软的重定向,否则您将无法再使用此史诗。

因此,我想说您希望大部分逻辑都封装在switchMap中:

function withAuthorizedFlow(source) {
  return source
    .map(fetchAssetListSuccess)
    // retryWhen takes a callback which accepts an Observable of errors
    // emitting a next causes a retry, while an error or complete will
    // stop retrying
    .retryWhen(e => e.flatMap(err => 
      Observable.if(
        // Returns the first stream if true, second if false
        () => err.status === 401,
        reauthenticate, // A stream that will emit once authenticated
        Observable.throw(err) // Rethrow the error
      ))
    )
    .catch(redirectToSignIn);
}
/** Within the epic **/
.switchMap(({payload}) => {
  const options = {
    crossDomain: true,
    withCredentials: true,
    url: uriGenerator('assetList', payload)
  };
  // Invoke the ajax request
  return ajax(options)
    // Attach a custom pipeline here
    // Not strictly necessary but it keeps this method clean looking.
    .let(withAuthorizedFlow);
})

上面的let的使用是完全可选的,我将其扔进去清理功能。从本质上讲,尽管您想将错误包含到内流流,以免它停止外部流。我不确定您使用的是哪个ajax库,但您还应该确认它实际上会返回冷Observable,否则您需要将其包装在defer块中才能使retryWhen工作。

最新更新