【问题标题】:HTTP Request retry on particular error using interceptor and retrywhenHTTP 请求使用拦截器重试特定错误并重试
【发布时间】:2018-11-14 02:52:07
【问题描述】:

我有一个调用 GET API 并收到响应的服务。我已经实现了 HTTP 拦截器来正确和全局地处理应用程序中的任何错误。我想做的是,当我的 API 返回特定错误时,例如错误 501,我需要在每次请求之前重试该请求 n 次和 t 秒延迟。如果我的重试结束,我还想处理一般错误(即,如果我在最后一次重试时出错,我想以特定方式处理它)。请帮我弄清楚如何解决这个问题。

这一切都是使用 Angular 6 实现的,如果有正确的语法,我们将不胜感激。

谢谢

【问题讨论】:

    标签: angular interceptor retrywhen


    【解决方案1】:

    您可以考虑使用 RxJS 的 retryWhendelaytapscan 来执行此操作。类似于以下代码,其中 Angular 服务调用 Google API 来验证不在浏览器上运行的应用程序中的用户,例如桌面应用程序。此服务使用 RxJS 以特定时间间隔重试 REST API 调用,以防因互联网连接不稳定而失败:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { retryWhen, delay, tap, scan, concatMap } from 'rxjs/operators';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GoogleDeviceAuthService {
    
      private readonly client_id = "<client-id>";
      private readonly client_secret = "<client-secret>";
    
      private readonly userCodeRequest = {
        "client_id": this.client_id,
        "scope": "email profile"
      };
    
      private readonly pollGoogleAuthServerRequestTemplate = {
        "client_id": this.client_id,
        "client_secret": this.client_secret,
        "code": "",
        "grant_type": "http://oauth.net/grant_type/device/1.0"
      }
    
      private readonly userCodeUrl = "https://accounts.google.com/o/oauth2/device/code";
    
      private readonly pollGoogleAuthServerUrl = "https://www.googleapis.com/oauth2/v4/token";
    
      constructor(private readonly http: HttpClient) { }
    
      public getUserCode() {
        return this.http.post(this.userCodeUrl, this.userCodeRequest)
          .pipe(
            retryWhen(err => err.pipe(
              scan(
                (retryCount, err) => {
                  if (retryCount > 3)
                    throw err;
                  else
                    return retryCount + 1;
                }, 0
              ),
              delay(1000),
              tap(err => console.log("Retrying...", err))
            )));
      }
    
      public checkAuthServerForUserInput(deviceCode) {
        let pollGoogleAuthServerRequest = { 
            ...this.pollGoogleAuthServerRequestTemplate, 
            ...{ "code": deviceCode } };
        return this.http.post(this.pollGoogleAuthServerUrl, pollGoogleAuthServerRequest)
          .pipe(
            retryWhen(err => err.pipe(
              scan(
                (retryCount, err) => {
                  if (retryCount > 3)
                    throw err;
                  else
                    return retryCount + 1;
                }, 0
              ),
              delay(1000),
              tap(err => console.log("Retrying...", err))
            )));;
      }
    }
    

    【讨论】:

    • 你认为这会覆盖我实现的拦截器吗?另外,我看到您使用 count 变量进行重试,我们可以改用 retry() 方法吗?
    • @KalyaniShirwalkar - 这与拦截器无关。所以,拦截器逻辑应该像往常一样工作。此处使用retryWhen 方法。我想有一个延迟,同时重试固定次数。我找不到更好的方法来实现这一点。也许有更好的方法,我目前不知道。
    • 实际上,有没有办法将其缩小到一个错误而不是全部?我尝试使用 error.status 但错误是 ProgressEvent 类型,它没有状态属性。
    • @KalyaniShirwalkar 我会尽快回复。但如果您赶时间,您可能想要console.log 错误对象并查看哪个字段包含状态。如果状态不是您想要的,请立即抛出错误。
    猜你喜欢
    • 1970-01-01
    • 2019-07-10
    • 2015-12-11
    • 1970-01-01
    • 2014-05-26
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-09-21
    相关资源
    最近更新 更多