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);
  }
}
4
  • 2
    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. Commented Jun 5, 2019 at 10:38
  • Press F12 and tell us what's on network. What do you see in response? Commented Jun 5, 2019 at 11:02
  • 1
    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/… Commented Jun 5, 2019 at 11:42
  • @JohnPeters network tab looks normal, the request is in there with a code of 200 and the content looks fine. Commented Jun 5, 2019 at 11:45

1 Answer 1

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();
      }
    });
  });
}
Sign up to request clarification or add additional context in comments.

2 Comments

Had a similar issue which I solved with .pipe(take(1))
Good find. Having a smiliar issue here 😰.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.