javascript - Angular2 http重试逻辑

标签 javascript http angular rxjs

我有一个具有基于 token 的身份验证机制的 API。成功登录后,我将两个 token 存储在浏览器的本地存储中——访问和刷新 token 。 访问 token 包含在服务器端授权用户所需的所有必要信息,并且具有到期日期。 当访问 token 过期时,客户端可以使用刷新 token 请求新的访问 token ,并在响应中获得一对新 token 。

在 Angular 1.x 中,实现非常简单明了。例如我们可以使用拦截器:

httpInterceptor.$inject = ['$httpProvider'];
function httpInterceptor($httpProvider) {
  $httpProvider.interceptors.push(handleStaleAccessToken);

  handleStaleAccessToken.$inject = ['$q', '$injector', 'session'];
  function handleStaleAccessToken($q, $injector, session) {

    function logoutAndRedirect() {
      var authenticationRedirect = $injector.get('authenticationRedirect');
      session.destroy();
      authenticationRedirect.toLoginPage();
    }

    return {
      responseError: function(rejection) {
        // Do nothing for non 403 errors
        if (rejection.status !== 403) {
          return $q.reject(rejection);
        }

        var errorCode = rejection.data.error && rejection.data.error.code;
        if (errorCode === 'access_token_expired') {
          var $http = $injector.get('$http');

          // Refresh token
          var params = { refreshToken: session.getRefreshToken() };
          return $http.post('/api/auth/refresh', params).then(function(response) {
            session.setTokens(response.data);
            // Re try failed http request
            return $http(rejection.config);
          }).catch(function(error) {
            logoutAndRedirect();
            return $q.reject(error);
          });
        } else {
          logoutAndRedirect();
        }

        return $q.reject(rejection);
      }
    };
  }
}

但是如何在angular 2/rxjs app中实现类似的逻辑呢?

最佳答案

这可以在 Angular2 中通过扩展 Http 类并利用 flatMap 等可观察运算符透明地完成。

下面是一些示例代码:

if (hasTokenExpired()) {
  return this.authService
             .refreshAuthenticationObservable()
             .flatMap((authenticationResult:AuthenticationResult) => {
                if (authenticationResult.IsAuthenticated == true) {
                     this.authService.setAuthorizationHeader(request.headers);
                  return this.http.request(url, request);
                }
                return Observable.throw(initialError);
    });
}

此代码必须集成到 Http 的自定义子类中:

一种方法是扩展 HTTP 对象以拦截错误:

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    console.log('request...');
    return super.request(url, options).catch(res => {
      // do something
    });        
  }

  get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    console.log('get...');
    return super.get(url, options).catch(res => {
      // do something
    });
  }
}

并按如下所述进行注册:

bootstrap(AppComponent, [HTTP_PROVIDERS,
    new Provider(Http, {
      useFactory: (backend: XHRBackend, defaultOptions: RequestOptions) => new CustomHttp(backend, defaultOptions),
      deps: [XHRBackend, RequestOptions]
  })
]);

有关更多详细信息,请查看这些问题:

关于javascript - Angular2 http重试逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36652495/

相关文章:

javascript - prototypejs - 使用类为按钮创建点击事件

Javascript 帮助使用 createElement() 和 appendChild()

http - 为什么在使用 Go HTTP 客户端时我的 HTTP POST 请求会有 60 秒的延迟?

可靠地设置 Etag

javascript - Angular 模块的 forRoot 中的运行时值

angular - 如何测试网格API是否可用于Angular中的ag-grid?

javascript - jstools build - JavaScript 在编译后出现问题

xml - 如何用 .net 和 XML 响应 HTTP GET

Angular5 HttpClient,在GET api调用后设置变量

javascript - JQuery 函数只是在第一次按下提交按钮时调用 Controller 操作