Angular HttpClient observable not completing
Asked Answered
I

1

8

I have the following code:

// in a service
downloadCSV(): Observable<Blob> {
  return this.httpClient.get(`${apiUrl}/a.csv`, {responseType: 'blob'});
}
// in component
onDownloadClicked(event: MouseEvent) {
  this.downloading = true;
  this.service.downloadCSV()
    .pipe(finalize(() => this.downloading = false))
    .subscribe(
      (data: Blob) => {
        console.log(data);
      },
      (error) => {
        console.error(error);
        alert('Sorry, something wet wrong. Try again.');
      },
      () => {
        console.log('completed!');
      }
    );
}

The data is logged correctly but 'completed!' is not logged and finalize is never called.

Edit:

So on further investigation, it seems the issue is related to an interceptor which adds an auth header.

If the interceptor is bypassed (and auth disabled on the server) the observable completes without error.

I don't understand why this is happening though. Possibly something related to the fact the request is cloned?

//interceptor code
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  let scope: string;
  // only inject tokens for the following scopes
  if (req.url.indexOf('https://graph.microsoft.com') === 0) {
    scope = 'https://graph.microsoft.com';
  }
  else if (req.url.indexOf('https://management.azure.com') === 0) {
    scope = 'https://management.azure.com';
  }
  else if (req.url.indexOf(environment.apiUrl) === 0) {
    scope = environment.appId;
  }
  if (scope) {
    return this.authService.getToken(scope).pipe(
      switchMap((token) => {
        let newReq;
        if (token) {
          const JWT = `Bearer ${token}`;
          newReq = req.clone({
            setHeaders: {
              Authorization: JWT,
            }
          });
        }
        return next.handle(newReq || req);
      })
    );
  }
  else {
    return next.handle(req);
  }
}
Intersperse answered 5/6, 2019 at 10:30 Comment(4)
Could not replicate locally - I see the completed callback get invoked when making an HttpClient#get with { responseType: 'blob' } and a finalize in the pipe.Mehala
Press F12 and tell us what's on network. What do you see in response?Pyramidal
I tried to create a stackblitz. Used the same versions of all the libraries but I can't replicate it either. It just works in the sb: stackblitz.com/edit/…Intersperse
@JohnPeters network tab looks normal, the request is in there with a code of 200 and the content looks fine.Intersperse
I
10

So it turns out the problem was in the getToken function of my auth service. I had forgotten to complete the observable after returning the token! Since the httpClient.get observable is switch mapped through my getToken observable it was causing my subscription in onDownloadClicked to never complete.

// from my auth service
getToken(resource: string): Observable<string> {
  return Observable.create((observer: Observer<string>) => {
    this.context.acquireToken(resource, (error, token) => {
      if (token) {
        observer.next(token);
        observer.complete(); // this was missing
      }
      else {
        this.login();
      }
    });
  });
}
Intersperse answered 5/6, 2019 at 14:1 Comment(2)
Had a similar issue which I solved with .pipe(take(1))Haemophiliac
Good find. Having a smiliar issue here 😰.Mulish

© 2022 - 2024 — McMap. All rights reserved.