9

I have a Java based API set up on a server. URL = "ex.com"

It has an endpoint which returns a PDF file. URL = "ex.com/pdf"

It expects a POST request with a parameter specifying which PDF is being requested. params = { location: "report.pdf"}

I would like to be able to use the Angular Http.post observable to get the PDF but it keeps throwing an HttpErrorResponse Http failure during parsing for http://ex.com/pdf ... Unexpected token % in JSON at position 0 at JSON.parse. But its a PDF I dont want it to be parsed as JSON.

This is my code:

params = {location: "report.pdf"};
return this.http.post<Response>("http://ex.com/pdf", params)
    .subscribe(
         data => {
            var file = new Blob([data], {type: 'application/pdf'});
            var fileURL = URL.createObjectURL(file);
            window.open(fileURL);
         }
     );

The endpoint works with PostMan. I can use the "Send and Download" option to successfully get the PDF file. So I just need to figure out how to do with in Angular. Appreciate the help.

Curtis
  • 3,170
  • 7
  • 28
  • 44
  • and the http error response message is?... – mast3rd3mon May 14 '18 at 14:11
  • then it looks like you're returning invalid JSON data – mast3rd3mon May 14 '18 at 14:15
  • sorry.. the error is "Http failure during parsing for http://ex.com/pdf" – Curtis May 14 '18 at 14:16
  • @mast3rd3mon the whole point is its not JSON. Its a PDF. The endpoint is valid. I just need to figure out how to get angular to work with it. – Curtis May 14 '18 at 14:17
  • if its not returning JSON, then you should probably send it as base64, that way it makes it easy to use – mast3rd3mon May 14 '18 at 14:18
  • You need to set the `responseType` of the request to `blob` – Brandon Taylor May 14 '18 at 14:22
  • @Brandon I tried that. It didnt work. Same Error – Curtis May 14 '18 at 14:31
  • I've had to do the same thing for a couple of different Angular applications recently, and setting the responseType on the request is working for me. Are you positive you set the responseType on the request and not the params passed to the new blob? – Brandon Taylor May 14 '18 at 14:36
  • @Brandon do you mean changing the response type on the server to blob (instead of application/pdf etc)? Or do you mean changing the line `this.http.post` to `this.http.post`? Because I tried the latter. I just realized the server was setting the content-type to application/octet-stream... so I am currently seeing if it makes a difference changing it to application/pdf – Curtis May 14 '18 at 14:46
  • @Brandon ... I figured out what you meant. Yes that worked. (well its at least not giving me the JSON Parse issue) I still need to work on getting the PDF to show up.. but that might be because its an octet stream instead of a PDF... Will look into it – Curtis May 14 '18 at 15:06
  • Glad that helped. On the server side, I'm leveraging PDFKit on the Node side, which just outputs a readable stream. – Brandon Taylor May 14 '18 at 15:20

1 Answers1

16

Try with something like this...

First of all, you will need file-saver node package so run npm install --save file-saver.

Then, try with something like this, I copy-paste my code that I used for something similar

public downloadPDF(): any {
    var mediaType = 'application/pdf';
    this.http.post(this.myUrl, {location: "report.pdf"}, { responseType: 'blob' }).subscribe(
        (response) => {
            var blob = new Blob([response], { type: mediaType });
            saveAs(blob, 'report.pdf');
        },
        e => { throwError(e); }
    );
}

This worked for me, but it was just for saving the file.

Let me know if it works!


UPDATE - ANGULAR7 & FILESAVER V.^2.0.1+


I've just migrated my app from Angular v.6 and Filesaver v.<2.0.1 (don't know what version it was but it was a previous one of 2.0.1).
In this new version, you'll have to change the import from:

import { saveAs } from 'file-saver/FileSaver';

to

import { saveAs } from 'file-saver';

Everything else works like previous version!

Deadpool
  • 1,031
  • 3
  • 19
  • 35
  • So I got it working by doing the create URL and putting it in an iframe. When I try and do window.open if looks like it opens the tab and then instantly closes it, even with popup blocker turned off... as for saving.. I tried that as well and the downloaded pdf doesnt open. It just says "Failed to open pdf" – Curtis May 14 '18 at 16:05
  • hmmm nvm it seems to be working now. For some reason it was creating the pdf with the text "[Object object]" in the file. Which is obv not a pdf file. But idk why I must have done something wrong cause its working now with the Save – Curtis May 14 '18 at 16:09
  • 1
    ad blocker was causing the popup not to work. Just an FYI to future people. – Curtis May 14 '18 at 16:27
  • @Curtis Wait, I'm trying to understand the current situation... So... Does it works now? Are you still facing any issue with this? – Deadpool May 14 '18 at 16:33
  • Yes it works. I am not able to do saveAs and get the pdf, or winodw.open and view the pdf in a new tab. Thanks for the help. – Curtis May 14 '18 at 16:43
  • @Curtis you're welcome! :) For opening the file, I don't know if it's a good practice to open the file from the user's device by the app once downloaded... I think it would be better to open it from the server but only if your app is not going to be used by a lot of users. Downloading it and letting the user decide when and if to open it could be the best practice – Deadpool May 15 '18 at 07:12
  • @Curtis Also, I suggest you to pay attenction on the use of `window` Javascript function. It could create problems in server side rendering. There are a lot of articles and questions about this, I link a question here...see [Luca Taccagni's answer](https://stackoverflow.com/questions/49981555/) to this user's question for more, but you can find easily other questions here on stackoverflow or surfing the internet! :) – Deadpool May 15 '18 at 07:13