【问题标题】:Change header on HTTP when retrying an Observable重试 Observable 时更改 HTTP 标头
【发布时间】:2017-05-31 04:38:10
【问题描述】:

我正在尝试在我的 Angular2 应用程序上实现刷新令牌。 我采取了一种乐观的方法,而不是在发出请求之前检查访问令牌是否过期,而是发出请求,如果它返回 401 代码,我将通过请求新的访问令牌并将其保存到本地存储来刷新访问令牌.

这是我的代码 sn-p:

   getWithParams<T>(serviceUrl: string, params: URLSearchParams): Observable<T> {
    return super.getWithParams<T>(serviceUrl, params)
        .retryWhen((error) => {
            return error
                .filter((e) => e.status === 401)
                .scan((acc, value) => {
                    return acc + 1;
                }, 0)
                .takeWhile(acc => acc < 3)
                .flatMap(() => this.tokenRefreshService.refreshToken())
                .delay(1000);
        });
}

值得一提的是,super.getWithParams 通过从本地存储中检索请求标头来设置访问令牌。

方法调用tokenRefreshService.refreshToken()获取一个新的访问令牌并保存到本地存储。

我面临的问题是,当重试请求时,它使用的是旧的访问令牌,也就是说,它没有调用 super.getWithParams 再次重建请求。它只是重试现有的 observable。

有没有办法再次构建请求?或链接失败的可观察对象的请求标头?

【问题讨论】:

标签: angular typescript rxjs observable


【解决方案1】:

实际上retryWhen() 重新订阅了它的来源,以便您可以利用它来发挥自己的优势。这个例子应该模拟你的情况:

let token = 'token';
let counter = 0;

const source$ = Rx.Observable.defer(() => {
    console.log('Observable.defer(), token: ' + token);
    return Rx.Observable.of(token);
  })
  .map(token => {
    if (counter++ < 3) {
      throw new Error('invalid token');
    }
    return token;
  })
  .retryWhen((error) => {
    return error
      .filter(() => true) // or whatever...
      .do(() => token = token + 'bla'); // update the token
  })
  .map(token => { // create the request
    return "I'm a request with token: " + token;
  });


source$.subscribe(
  res => console.log(res),
  err => console.log('error: ' + err),
  () => console.log('complete')
);

观看现场演示:https://jsbin.com/roduqi/5/edit?js,console

这 3 次抛出一个错误,令牌无效,并且每次都更新它。

请注意,每次出现错误时,我都会使用 Observable.defer 创建一个新的 Observable 源。

这个例子打印到控制台:

Observable.defer(), token: token
Observable.defer(), token: tokenbla
Observable.defer(), token: tokenblabla
Observable.defer(), token: tokenblablabla
I'm a request with token: tokenblablabla
complete

【讨论】:

  • 将 super.getWithParam 方法调用包装在一个 observable 中就可以了。太棒了!
  • 将 defer 添加到我的 observable 就像魅力一样。我为此花了 4 个小时,谢谢@martin!
  • @martin 我可以在角度拦截器中使用它来操纵http请求吗?所以基本上返回 next.handle(request).pipe(retryWhen...? 所以基本上如果一个请求第一次失败,重试但是在请求中添加一个参数以知道它是重试,因为我需要这个信息沿着这条路走得更远.
猜你喜欢
  • 1970-01-01
  • 2014-08-23
  • 2016-11-19
  • 2014-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-08
相关资源
最近更新 更多