6

I'm receiving a byte array from server side and has converted it successfully to blob. However, when I'm trying to download it, it shows the file is corrupted. Below are my codes -

// In client side controller
this.contractsService.downloadPdf(id)
      .then((result) => {
        var blob = new Blob([result], { type: "application/pdf" });
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = "testing.pdf";
        link.click();
      });

And,

// In client side service
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
downloadPdf(id: number) {
    return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers })
      .map((res: any) => res)
      .toPromise();
  }

Any sort of help will be very much appreciated. Thank you.

Raj
  • 417
  • 1
  • 3
  • 17
  • Look into the documentation for the http client that does the ajax request. You need to make sure that the generated `result` is a Blob (treated as binary) and not a string (treated with shenanigans and evil encodings). This is probably another parameter or setting to the `this.http.get(...)` call. – sisve Mar 13 '18 at 07:35

2 Answers2

6

Install file-saver

npm i --save file-saver@latest

Your service method

downloadPdf(id: number) {
    return this.http
              .get(this.apiRoutes.download + "/" + id, { responseType:'blob' })
      .toPromise();
  }

Now in your component

import { saveAs } from 'file-saver'

this.contractsService.downloadPdf(id)
      .then(blob=> {
         saveAs(blob, 'testing.pdf');
      });

This should do the trick. The HttpClient will now extract the file from the stream. Also have a look in the documentation for blobs with the HttpClient.

alsami
  • 8,996
  • 3
  • 25
  • 36
  • When you open the url of your api directly via browser and download the file, does it work? Either u are using legacy http client or the file that is served is corrupt in the first place. – alsami Mar 13 '18 at 09:17
  • When I'm downloading the file on the server side locally, it works perfectly. However, when I'm converting it to byte array and sending to the client side for downloading, it's getting corrupted. P.S. no, the file is showing corrupted when I open it manually from the URL as well. – Raj Mar 13 '18 at 09:20
  • Ah okay, then it is your API that is doing wrong, not the client. – alsami Mar 13 '18 at 09:21
  • Locally as in, when I create the file using File class. – Raj Mar 13 '18 at 09:23
  • Yeah is the API that ir returning the file corrupted, is not the client. Provide the API code and I may help you. – alsami Mar 13 '18 at 09:24
  • Is there any possible way to download the file from angular 5, "without" creating a temporary file on the server side? – Raj Mar 13 '18 at 09:24
  • 1
    You don't need to provide a temporary file, just a byte array and a filecontent-result. Please see https://stackoverflow.com/a/48864842/5397642 – alsami Mar 13 '18 at 09:27
  • Thanks a lot. FileContentResult was the thing that I was missing and I didn't know about it either. However, using it, resolved the issue. Still, can you please clarify a bit about FileContentResult class? Thanks a lot once again :) – Raj Mar 13 '18 at 10:07
  • 1
    It's just a class that implements IActionResult and returns a file as byte array. Will set special response headers like content-disposition, file name and so on. You can read more about it here https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filecontentresult?view=aspnetcore-2.0 – alsami Mar 13 '18 at 10:09
0

In client side service, try explicitly setting the response type of the get request:

downloadPdf(id: number) {
    return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers; responseType: 'arraybuffer' })
      .map((res: any) => res)
      .toPromise();
  }
user2590928
  • 176
  • 10