5

I have a AngularJs frontend and a NodeJS backend. I am trying to build a PDF on NodeJS based on some parameters from AngularJS and return the PDF in response.

The code I am using seems to work fine when I make a GET request from AngularJS, but it returns a blank PDF when I make a POST request. I need to make a POST request since I have to send some specific data.

I am saving the file on disk first and then sending it to the frontend so I can see that the PDF is being generated correctly. It's either not being sent correctly or read correctly at the FrontEnd.

Following is my AngularJS code

var url = {{My Node Server URL}};
            (Note: Works when I make a Get request, without sending post params)
            var $promise = $http.post(encodeURI(url), {
                    responseType: 'arraybuffer',
                    competitors: competitors,
                    channels: channels
            });

            $promise.then(

                function success(response) {


                    var blob = new Blob([response.data], { type : 'application/pdf' });
                    var pdfLink = (window.URL || window.webkitURL).createObjectURL( blob );

                    window.open(
                      pdfLink,
                      '_blank' // <- This is what makes it open in a new window.
                    );

                    cb(pdfLink);

              }, function error(response) {

                --Error Handling--
              }
           )

Following is my NodeJS code

wkhtmltopdf(
            html,
            { 
                output: pdfName
            },
            function (code, signal) {
                fs.readFile(pdfName, function (err, data) {
                    if (err) {res.writeHead(400); res.end("" + err); return;}

                    res.writeHead(
                        200,
                        {
                            "content-type" : "application/pdf",
                            "Content-Disposition": "attachment; filename=Best.pdf "
                        }
                    );
                    res.end(data);
                });     
            }
        );

I have looked into a lot of places and tried almost everything but nothing seems to be working. Any hint/help/suggestion would be appreciated. Kindly ask if I need to provide any more info or details. TIA

Sambhav Sharma
  • 5,741
  • 9
  • 53
  • 95
  • You need to post the code that retrieves the parameters from the request in your framework. Likely you are not fetching it in the same way as in a get request. – Peter Ashwell Jan 25 '15 at 23:32
  • Nope, it has nothing to do with the parameters.. I am able to get the params from both the requests. Like I said the PDF is being generated fine in both the cases. I can check it on the server. The difference is that it shows blank on the frontend when I use a POST request. I know it is really strange! :( Thanks a lot for taking your time out.. And for asking for clarification.. – Sambhav Sharma Jan 25 '15 at 23:34

2 Answers2

10

Got it! I just had to add responseType as arraybuffer as another argument. I think this is self explanatory as to why this worked. So the following code worked!

var $promise = $http.post(encodeURI(url), {
                    competitors: competitors,
                    channels: channels
            },{responseType: 'arraybuffer'});
Sambhav Sharma
  • 5,741
  • 9
  • 53
  • 95
  • 1
    Thank you, thank you, thank you! This brought a number of hours of work to a close for me. Until I added {responseType: 'arraybuffer'} to my api call I was still receiving the data, I was able to save it off and Adobe Reader was still opening up my PDF without an error. The problem? The PDF was larger size than the original file... and when displayed, it was blank. Once I added in the responseType property, viola! Thanks again. – Marcidius Apr 18 '16 at 15:31
  • For me it didn't work until I've set responseType to blob, not to arrayBuffer: http://stackoverflow.com/a/43041245/3093041 – ancab Mar 27 '17 at 08:21
2

For anyone having issues with this scenario that is using Angular 2+, the solution is the same but is executed differently. See: https://angular.io/docs/ts/latest/api/http/index/ResponseContentType-enum.html

In my application, I passed a doc name to my express server, which passes the file back with res.download(filename).

Front end service looks as follows:

downloadDoc(docName: string) {
  let pkg = {docName: docName};
  let opts = new RequestOptions({
    responseType: ResponseContentType.ArrayBuffer
  });
  return this.http
          .post(this.baseUrl + '/downloadDoc', pkg, opts)
          .toPromise()
          .then((res: any) => {
            let blob = new Blob([res._body], {type: 'application/pdf'});
            return blob;
          });
}
Daynil
  • 1,528
  • 3
  • 17
  • 20