I have a VueJS frontend that is connected to a Rails API backend.
In one of the endpoints, I am using WickedPDF to generate a PDF. When I open the URL itself in a browser, the PDF downloads fine and works exactly as expected. When I send a request via Vue, the API responds with a weird looking string that looks like this:
%PDF-1.4
1 0 obj
<<
/Title (��)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20190222102025+02'00')
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
...
I am not really sure what data type this is? I initially thought that it might be a BLOB, but I have no idea. I followed the logic outlined here to parse the response from my rails api, which did download a PDF to chrome. When opening this PDF, it is blank and the file name at the top of the chrome browser is a combination of weird chars. This makes me think that I am not converting the response in the correct way and some encoding issue ends up happening.
Here is my Rails API code:
def pdf
pdf_html = ActionController::Base.new.render_to_string(
template: 'api/v1/exporters/pdf',
layout: 'pdf',
page_size: 'A4',
formats: :html,
encoding: 'utf8',
margin: {
top: 20,
left: 20,
}
)
pdf = WickedPdf.new.pdf_from_string(pdf_html)
send_data(
pdf,
filename: 'download.pdf',
type: 'application/pdf',
disposition: 'attachment'
)
end
Here is the JS function from the link above. I am passing the Rails response body (which when console logged is the weird looking char set in the first code block) as the only param:
showFile(blob){
var newBlob = new Blob([blob], {type: "application/pdf"})
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
const data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
link.href = data;
link.download="file.pdf";
link.click();
setTimeout(function(){
window.URL.revokeObjectURL(data);
, 100}
}
Can anyone help point me in the right direction as to how to configure this in the right way or how to do it in a different/better way? Even a confirmation of what kind of data type the response is might help me.
If you are using axios for the API call, you can specify the client to download the data as blob.
import axios from 'axios';
axios
.request({
url: '/api-url-to-download-pdf',
responseType: 'blob',
})
.then(response => response.data)
.then(blob => {
const data = URL.createObjectURL(blob );
// ... do your stuff here ...
.catch((err) => {
// handle error
});
If you are using fetch api to make the API request,
fetch('/api-url-to-download-pdf', {
headers: {
Accept: 'application/pdf',
},
responseType: 'arraybuffer'
})
.then(response => {
console.log(response);
if (response.ok) {
return response.blob();
}
})
.then(blob => {
const data = URL.createObjectURL(blob);
// ... do your stuff here ...
})
.catch((err) => {
// handle error
});