PDF Download in HREF of a-element results in empty PDF












2















I use a-element as download-button for files I have had to query with AJAX before as described here, here and here. I put to put the file-data as Data-URI into a a-element to create a download-button. Unfortunately I can not just point to the file but have to do it like that. With most download-formats HTML, CSV it works like this:



var mimeType = "text/html"; // example. works also with others.
var BOM = 'ufeff';
var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);
var linkElem = document.querySelector("#hiddenDownloadLink");
var link = angular.element(linkElem);
link.prop("href", url);
link.prop("download", 'myFile.' + extension);
linkElem.click();


Okay. That works. But not for PDF.



I create a PDF in my backend (java, with openhtmltopdf but it doesn't matter I guess, since the PDF is definitely correct):



httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/pdf");
httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="myFile.pdf"");
makePdf(httpOutputMessage.getBody());


If I query the backend directly, or even if I log the output into a file, everything is fine. But when I use my download-controller as described above, I get a PDF with the right number of pages but completely empty! I think there must be an encoding issue. I tried with and without BOM, also with or without encodeURIComponent.



I also tried to use the base64-decoding as. Because window.atob(response.data) fails because of line breaks and others, I tried this conversion. The result is an broken PDF. Results in broken PDFs. I am not sure if that makes any sense.



My PDF-data starts like this, so it's not compressed or encoded anyhow:



%PDF-1.4
%����
1 0 obj
<<
/Type /Catalog
/Version /1.7
/Pages 2 0 R
>>
endobj
3 0 obj
<<


I also tried to convert the bytestream to blob and generate a link as described here orhere, but that creates broken PDFs.



Any Ideas, why I get empty PDFs or what might go wrong here and how can I repait the download-link?



--
Edit 1



I also get valid, but blank PDF when I try



var blob = new Blob([response.data], {type: 'application/pdf'});
var url = window.URL.createObjectURL(blob);
link.prop("href", url);


When I pipe response.data through this function, I get a broken PDF.



var utf8_to_b64 = function(str) {
var unescape = window.unescape || window.decodeURI;
str = encodeURIComponent(str);
str = unescape(str);
str = window.btoa(str);

return str;
};









share|improve this question

























  • "since the PDF is definitely correct" - and how do you know this?

    – Ryan McDonough
    Nov 19 '18 at 10:30











  • As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

    – Paflow
    Nov 19 '18 at 13:29
















2















I use a-element as download-button for files I have had to query with AJAX before as described here, here and here. I put to put the file-data as Data-URI into a a-element to create a download-button. Unfortunately I can not just point to the file but have to do it like that. With most download-formats HTML, CSV it works like this:



var mimeType = "text/html"; // example. works also with others.
var BOM = 'ufeff';
var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);
var linkElem = document.querySelector("#hiddenDownloadLink");
var link = angular.element(linkElem);
link.prop("href", url);
link.prop("download", 'myFile.' + extension);
linkElem.click();


Okay. That works. But not for PDF.



I create a PDF in my backend (java, with openhtmltopdf but it doesn't matter I guess, since the PDF is definitely correct):



httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/pdf");
httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="myFile.pdf"");
makePdf(httpOutputMessage.getBody());


If I query the backend directly, or even if I log the output into a file, everything is fine. But when I use my download-controller as described above, I get a PDF with the right number of pages but completely empty! I think there must be an encoding issue. I tried with and without BOM, also with or without encodeURIComponent.



I also tried to use the base64-decoding as. Because window.atob(response.data) fails because of line breaks and others, I tried this conversion. The result is an broken PDF. Results in broken PDFs. I am not sure if that makes any sense.



My PDF-data starts like this, so it's not compressed or encoded anyhow:



%PDF-1.4
%����
1 0 obj
<<
/Type /Catalog
/Version /1.7
/Pages 2 0 R
>>
endobj
3 0 obj
<<


I also tried to convert the bytestream to blob and generate a link as described here orhere, but that creates broken PDFs.



Any Ideas, why I get empty PDFs or what might go wrong here and how can I repait the download-link?



--
Edit 1



I also get valid, but blank PDF when I try



var blob = new Blob([response.data], {type: 'application/pdf'});
var url = window.URL.createObjectURL(blob);
link.prop("href", url);


When I pipe response.data through this function, I get a broken PDF.



var utf8_to_b64 = function(str) {
var unescape = window.unescape || window.decodeURI;
str = encodeURIComponent(str);
str = unescape(str);
str = window.btoa(str);

return str;
};









share|improve this question

























  • "since the PDF is definitely correct" - and how do you know this?

    – Ryan McDonough
    Nov 19 '18 at 10:30











  • As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

    – Paflow
    Nov 19 '18 at 13:29














2












2








2








I use a-element as download-button for files I have had to query with AJAX before as described here, here and here. I put to put the file-data as Data-URI into a a-element to create a download-button. Unfortunately I can not just point to the file but have to do it like that. With most download-formats HTML, CSV it works like this:



var mimeType = "text/html"; // example. works also with others.
var BOM = 'ufeff';
var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);
var linkElem = document.querySelector("#hiddenDownloadLink");
var link = angular.element(linkElem);
link.prop("href", url);
link.prop("download", 'myFile.' + extension);
linkElem.click();


Okay. That works. But not for PDF.



I create a PDF in my backend (java, with openhtmltopdf but it doesn't matter I guess, since the PDF is definitely correct):



httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/pdf");
httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="myFile.pdf"");
makePdf(httpOutputMessage.getBody());


If I query the backend directly, or even if I log the output into a file, everything is fine. But when I use my download-controller as described above, I get a PDF with the right number of pages but completely empty! I think there must be an encoding issue. I tried with and without BOM, also with or without encodeURIComponent.



I also tried to use the base64-decoding as. Because window.atob(response.data) fails because of line breaks and others, I tried this conversion. The result is an broken PDF. Results in broken PDFs. I am not sure if that makes any sense.



My PDF-data starts like this, so it's not compressed or encoded anyhow:



%PDF-1.4
%����
1 0 obj
<<
/Type /Catalog
/Version /1.7
/Pages 2 0 R
>>
endobj
3 0 obj
<<


I also tried to convert the bytestream to blob and generate a link as described here orhere, but that creates broken PDFs.



Any Ideas, why I get empty PDFs or what might go wrong here and how can I repait the download-link?



--
Edit 1



I also get valid, but blank PDF when I try



var blob = new Blob([response.data], {type: 'application/pdf'});
var url = window.URL.createObjectURL(blob);
link.prop("href", url);


When I pipe response.data through this function, I get a broken PDF.



var utf8_to_b64 = function(str) {
var unescape = window.unescape || window.decodeURI;
str = encodeURIComponent(str);
str = unescape(str);
str = window.btoa(str);

return str;
};









share|improve this question
















I use a-element as download-button for files I have had to query with AJAX before as described here, here and here. I put to put the file-data as Data-URI into a a-element to create a download-button. Unfortunately I can not just point to the file but have to do it like that. With most download-formats HTML, CSV it works like this:



var mimeType = "text/html"; // example. works also with others.
var BOM = 'ufeff';
var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);
var linkElem = document.querySelector("#hiddenDownloadLink");
var link = angular.element(linkElem);
link.prop("href", url);
link.prop("download", 'myFile.' + extension);
linkElem.click();


Okay. That works. But not for PDF.



I create a PDF in my backend (java, with openhtmltopdf but it doesn't matter I guess, since the PDF is definitely correct):



httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/pdf");
httpOutputMessage.getHeaders().add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="myFile.pdf"");
makePdf(httpOutputMessage.getBody());


If I query the backend directly, or even if I log the output into a file, everything is fine. But when I use my download-controller as described above, I get a PDF with the right number of pages but completely empty! I think there must be an encoding issue. I tried with and without BOM, also with or without encodeURIComponent.



I also tried to use the base64-decoding as. Because window.atob(response.data) fails because of line breaks and others, I tried this conversion. The result is an broken PDF. Results in broken PDFs. I am not sure if that makes any sense.



My PDF-data starts like this, so it's not compressed or encoded anyhow:



%PDF-1.4
%����
1 0 obj
<<
/Type /Catalog
/Version /1.7
/Pages 2 0 R
>>
endobj
3 0 obj
<<


I also tried to convert the bytestream to blob and generate a link as described here orhere, but that creates broken PDFs.



Any Ideas, why I get empty PDFs or what might go wrong here and how can I repait the download-link?



--
Edit 1



I also get valid, but blank PDF when I try



var blob = new Blob([response.data], {type: 'application/pdf'});
var url = window.URL.createObjectURL(blob);
link.prop("href", url);


When I pipe response.data through this function, I get a broken PDF.



var utf8_to_b64 = function(str) {
var unescape = window.unescape || window.decodeURI;
str = encodeURIComponent(str);
str = unescape(str);
str = window.btoa(str);

return str;
};






javascript pdf data-uri






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 '18 at 10:17







Paflow

















asked Nov 15 '18 at 14:59









PaflowPaflow

419622




419622













  • "since the PDF is definitely correct" - and how do you know this?

    – Ryan McDonough
    Nov 19 '18 at 10:30











  • As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

    – Paflow
    Nov 19 '18 at 13:29



















  • "since the PDF is definitely correct" - and how do you know this?

    – Ryan McDonough
    Nov 19 '18 at 10:30











  • As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

    – Paflow
    Nov 19 '18 at 13:29

















"since the PDF is definitely correct" - and how do you know this?

– Ryan McDonough
Nov 19 '18 at 10:30





"since the PDF is definitely correct" - and how do you know this?

– Ryan McDonough
Nov 19 '18 at 10:30













As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

– Paflow
Nov 19 '18 at 13:29





As I wrote - I tested to call the backend directly with postman, and I wrote a pdf-file from backend on the servers harddrive, and in both cases it got a correct pdf with contents.

– Paflow
Nov 19 '18 at 13:29












1 Answer
1






active

oldest

votes


















1





+50









So I could fully reproduce your situation. I loaded and output a 4 page PDF file through an AJAX request from backend, and with your code example got a 4 page blank PDF.



Here's what I did after (and got the right PDF to download):



I base64 encoded the output from the backend. In my case I was using PHP so it was something like this:



$pdf = file_get_contents('test.pdf');
header('Content-Type: application/pdf');
echo base64_encode($pdf);


Then in the frontend I changed only this line:



var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);


to this:



var url = "data:"+ mimeType +";base64," + encodeURIComponent(response.data);


Hope this helps.






share|improve this answer
























  • It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

    – Paflow
    Nov 29 '18 at 18:09











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322226%2fpdf-download-in-href-of-a-element-results-in-empty-pdf%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1





+50









So I could fully reproduce your situation. I loaded and output a 4 page PDF file through an AJAX request from backend, and with your code example got a 4 page blank PDF.



Here's what I did after (and got the right PDF to download):



I base64 encoded the output from the backend. In my case I was using PHP so it was something like this:



$pdf = file_get_contents('test.pdf');
header('Content-Type: application/pdf');
echo base64_encode($pdf);


Then in the frontend I changed only this line:



var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);


to this:



var url = "data:"+ mimeType +";base64," + encodeURIComponent(response.data);


Hope this helps.






share|improve this answer
























  • It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

    – Paflow
    Nov 29 '18 at 18:09
















1





+50









So I could fully reproduce your situation. I loaded and output a 4 page PDF file through an AJAX request from backend, and with your code example got a 4 page blank PDF.



Here's what I did after (and got the right PDF to download):



I base64 encoded the output from the backend. In my case I was using PHP so it was something like this:



$pdf = file_get_contents('test.pdf');
header('Content-Type: application/pdf');
echo base64_encode($pdf);


Then in the frontend I changed only this line:



var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);


to this:



var url = "data:"+ mimeType +";base64," + encodeURIComponent(response.data);


Hope this helps.






share|improve this answer
























  • It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

    – Paflow
    Nov 29 '18 at 18:09














1





+50







1





+50



1




+50





So I could fully reproduce your situation. I loaded and output a 4 page PDF file through an AJAX request from backend, and with your code example got a 4 page blank PDF.



Here's what I did after (and got the right PDF to download):



I base64 encoded the output from the backend. In my case I was using PHP so it was something like this:



$pdf = file_get_contents('test.pdf');
header('Content-Type: application/pdf');
echo base64_encode($pdf);


Then in the frontend I changed only this line:



var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);


to this:



var url = "data:"+ mimeType +";base64," + encodeURIComponent(response.data);


Hope this helps.






share|improve this answer













So I could fully reproduce your situation. I loaded and output a 4 page PDF file through an AJAX request from backend, and with your code example got a 4 page blank PDF.



Here's what I did after (and got the right PDF to download):



I base64 encoded the output from the backend. In my case I was using PHP so it was something like this:



$pdf = file_get_contents('test.pdf');
header('Content-Type: application/pdf');
echo base64_encode($pdf);


Then in the frontend I changed only this line:



var url = "data:"+ mimeType +";charset=UTF-8," + BOM + encodeURIComponent(response.data);


to this:



var url = "data:"+ mimeType +";base64," + encodeURIComponent(response.data);


Hope this helps.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 25 '18 at 21:36









Dan D.Dan D.

580313




580313













  • It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

    – Paflow
    Nov 29 '18 at 18:09



















  • It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

    – Paflow
    Nov 29 '18 at 18:09

















It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

– Paflow
Nov 29 '18 at 18:09





It helped because I realized that I had to do the BASE64 by myself. Then I used your url and it worked. Except that now you can not access backend directly, but that's not necessary.

– Paflow
Nov 29 '18 at 18:09




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322226%2fpdf-download-in-href-of-a-element-results-in-empty-pdf%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Xamarin.iOS Cant Deploy on Iphone

Glorious Revolution

Dulmage-Mendelsohn matrix decomposition in Python