Angular 5 / HttpInterceptor / Detect(已取消)xhr

时间:2018-05-04 09:48:37

标签: angular httpclient angular-http-interceptors

在我的角度应用程序中,我看到chrome(取消)api调用太快了。我还有一个HttpInterceptor,如果请求没有完成,它会在500ms后触发每个HttpClient请求的加载指示符。但是,在获取(取消)的请求中,似乎没有任何新事件随后隐藏我的加载指示符。

有没有办法在HttpInterceptor中检测'已取消'的请求,以便我可以再次隐藏我的加载指示符?

export class GlobalHttpInterceptor implements HttpInterceptor {
constructor(
private sessionService: SessionService,
private loadingService: LoadingService
) { }

intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {

setTimeout(() => {
  if (showLoading) {
    this.loadingService.show();
  }
}, 500);
let showLoading = true;

if (this.sessionService.headers.length > 0) {
  for (const x of this.sessionService.headers) {
    req = req.clone({
      headers: req.headers.set(x.key, x.value)
    });
  }
}

return next.handle(req)
  .do(
    (response) => {
      if (response instanceof HttpResponse) {
        showLoading = false;
        this.loadingService.hide();
      }
    },
    (error) => {
      showLoading = false;
      this.loadingService.hide();
    });
}
}

3 个答案:

答案 0 :(得分:11)

刚遇到同样的问题。即使http请求被取消, finalize 运算符似乎也会触发。

public intercept(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    // request starts

    return next.handle(request).pipe(
        finalize(() => {
            // request completes, errors, or is cancelled
        })
    );
}

答案 1 :(得分:0)

不确定为什么 @Davy 提供的答案尚未标记为绿色。 这是一种可行的解决方案,无需遵循可中止的获取就可以使用。

这里是工作中的demo built with Angular 8

尝试通过网络限制(例如“慢速3G”)进行尝试,并注意到在应用程序的请求队列中至少有一个HTTP请求时,每次都会显示一个精美的动画圆圈(请参阅源代码)。

如果您仔细观察网络请求,您会发现先前的未决XHR请求在收到用户的新输入后将被取消(请注意,GitHub API对一些HTTP GET请求施加了限制,因此请使用明智地,否则您将获得403 HTTP状态代码)。 @Davy提出的方法可以很好地工作,除非您做一些花哨的操作并在有待处理的请求时按Cmd + S(在PC上为Ctrl + S)。 在这种情况下,将不会调用finalize处理程序,因为整个过程都被本机模态对话框中断。

答案 2 :(得分:0)

扩展Davy的答案,这就是我检测到中止请求的方式。

正如他所说,finalize将始终在可观察到的源完成上运行,在这种情况下,它是成功响应,错误响应或中止的请求。

我的方法的关键是跟踪您到目前为止所收到的信息。

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  let lastResponse: HttpEvent<any>;
  let error: HttpErrorResponse;

  return next.handle(request)
    .pipe(
      tap((response: HttpEvent<any>) => {
        lastResponse = response;
        if (response.type === HttpEventType.Response) {
          console.log('success response', response);
        }
      }),
      catchError((err: any) => {
        error = err;
        console.log('error response', err);
        // TODO: error handling if required
        return throwError(err);        
      }),    
      finalize(() => {
        if (lastResponse.type === HttpEventType.Sent && !error) {
          // last response type was 0, and we haven't received an error
          console.log('aborted request');
        }
      })
    );
}