Tel Map

Blog

Angular 5 HttpClient File Download with Authentication

This article describes how a typical browser file download can be triggered using the Angular HttpClient. Typically you can simply introduce a link to the endpoint of the file download into the page and this will work just fine. However, if you use authentication via bearer token etc. and the download endpoint needs authentication, you probably want to use the HttpClient in order to make that download request.

To see how to add a bearer token to all http requests in Angular see one of my previous articles:

Angular 5 HttpInterceptor – Add Bearer Token to HttpClient Requests

In this article I will use a zip file as an example.

Download file as Blob

First of all we need to download the file as a blob object. Therefore we introduce a new service method.

I like working with Promises and async in my code…

Keep a close look at the response type here. It has to be set to ‘blob’. Unfortunately simply setting this to blob leads to a TypeScript error:

So you really have to put in this hack and do a “as ‘json'” in order for this to work.

Triggering a file download

In order to open a save file dialog you have to create an object URL with the blob you get from the service above and then “open” that URL.

I couple of things to note here…

First of all an object created by createObjectURL should also be revoked afterwards with revokeObjectURL.

window.open(url)

I saw a lot of example code that worked with window.open(url) instead of the code I use to open the file saving dialog.

Window.open triggered my popup blocker and some browsers specifically asked if they should open this URL. So this solution did not work for me.

Using a link with a click event

I simply inserted a new link into my page and set it to display none.

Afterwards you can reference that element by introducing

in your component.

This solutions has the advantage that you can

a) revoke the object easily afterwards and

b) you can specify a name for the downloaded file.

Then you just call the click event of that link and the download will be started. Obviously it is also easy to put in some spinner code etc…

One remark here…. since the file first gets downloaded as a Blob, then an objectURL gets created etc., this whole process might not be feasible for large download files.

If you have questions or comments, please leave them below.

 

 

 

 

18 Replies to “Angular 5 HttpClient File Download with Authentication”

  1. Sam B

    Shouldn’t this line

    const blob = await this.service.downloadZip(this.id);

    be

    const blob = await this.service.downloadResource(this.id);

    1. Sebastian Lindner Post author

      You are right… probably a mistake I introduced for adjusting the code for the blog post

  2. Thank you for this. You saved the day. Although my http get is without and only with ‘blob’. There is some angular 5 issue with this.

    Whole service method:

    getShipmentAttachment(shipmentId: number, attachmentId: number): Observable {

    let url: string = this.getFullUrl(/api/v1/shipments/${shipmentId}/attachments/${attachmentId});
    let headers: HttpHeaders = new HttpHeaders().set(‘Authorization’, this.token);

    return this._httpClient.get(url, {
    headers: headers,
    responseType: ‘blob’ // very important that this is set
    })
    .pipe(
    catchError(this.handleError)
    );
    }

  3. Rob

    This won’t work at all in Angular 6 typescript.
    Also why are you using promises when Angular 2 + has Observables ?

    My service function:
    getEvidenceFile(id: number, getFileContent: boolean) {

    return this.http.get(environment.baseUrl + ‘upload’ + ‘/’ + id + ‘,’ + getFileContent, {responseType: ‘blob’ as ‘json’})
    .map(res => res);
    }

    My component function called from the selected item of a dropdown…
    dropDownValue(event: any) {

    // const blob = await this.callService.getEvidenceFile(event.target.value, true);
    // const url = window.URL.createObjectURL(blob);

    this.callService.getEvidenceFile(event.target.value, true).subscribe(data => {

    var binaryData = [];
    binaryData.push(data);
    var downloadLink = document.createElement(‘a’);
    downloadLink.href = window.URL.createObjectURL(new Blob(binaryData));
    document.body.appendChild(downloadLink);
    downloadLink.click();

    });
    }

    [ts] Property ‘URL’ does not exist on type ‘ (this: Observable , windowBoundaries: Observable) => Observable<Observable>’.

  4. chadbr

    This was very helpful.

    > I like working with Promises and async in my code…

    +1 – friends don’t let friends do rx

  5. tatsu

    createObjectURL went into deprecation 7 years ago and has been effectively deprecated 2 years ago this guide has been unusable for two years. please update it.

    1. Hi tatsu,
      Do you have any source for this? I looked at the Mozilla documentation for URL.createObjectURL and there is no sign of a deprecation: https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL with full support in all major browsers.

      There seems to be a change however, when using a MediaStream with an HTMLMediaElement (like Video) which used to utilize URL.createObjectURL, but doesn’t any more : https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
      Maybe this is what you are referring to?

  6. Jack

    This is great, even years later. Had exactly this scenario, but most examples have you use href to api call which doesn’t work in real authentication scenarios. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *