RxJs Observables:在更多异步请求后运行 retryWhen [英] RxJs Observables: run retryWhen after some more async requests

查看:47
本文介绍了RxJs Observables:在更多异步请求后运行 retryWhen的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的用例是:

  1. 用户从我们的 API 请求资产,但由于 JWT 过期(作为 httpOnly cookie 传递)而失败 - API 返回 401 状态代码.
  2. 我们再次使用 refresh_token 对它们进行身份验证(无需用户执行任何操作),以通过客户端向 auth0 的请求检索新的 JWT.
  3. 我们将新的 JWT 发送到我们的 API,以将其设置为 httpOnly cookie 以替换过期的 cookie.
  4. 然后,我们要重试用户在第 1 步中向 API 发出的原始请求.

我正在尝试在我的 Redux 应用程序中使用 Observables 和 redux-observable.如果您能想到另一种使上述用户流工作的方法,我很乐意听到.

I'm trying to use Observables within my Redux app with redux-observable. If you can think of another way of making the above user flow work I would be happy to hear how.

注意.我使用 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 步的方法.我可能完全偏离目标,但任何帮助都会很棒!

So far I able to complete steps 1, 2 and 3 but not too sure of a way to add step 4. I may be completely off the mark but any help would be great!

推荐答案

好吧,您可能不想做的一件事是让错误进入顶级流.即使你做了一个catch,你也有效地杀死了顶级流.因此,除非您的重定向通过 react-router 之类的方式进行硬重定向而不是软重定向,否则您将无法再使用此史诗.

Well one thing you probably won't want to do is allow the error to make it to the top level stream. Even if you do a catch you have effectively killed the top level stream. So unless your redirect is doing a hard redirect instead of a a soft one via something like react-router, you won't be able to use this epic any more.

因此我会说您希望将大部分逻辑封装在 switchMap 中:

Thus I would say that you want most of the logic to be encapsulated within the 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 工作.

The use of let above is completely optional, I threw it in to clean up the function. Essentially though you want to contain the error to the inner stream so that it can't halt the outer one. I am not sure which ajax library you are using but you should also confirm that it will in fact return a cold Observable otherwise you will need to wrap it in a defer block to in order for the retryWhen to work.

这篇关于RxJs Observables:在更多异步请求后运行 retryWhen的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆