Download pdf from REST API with correct encoding - javascript

I'm trying to download pdf file from rest api using those two methods:
download(): ng.IPromise<Blob> {
return this.$http.get<ArrayBuffer>(this.urls.getUrl())
.then(response => {
return new Blob([response.data], {type: 'application/pdf'});
}
)
}
this.service.download().then( file => {
var a = document.createElement("a"),
url = URL.createObjectURL(file);
open(url)
a.href = url;
a.download = 'invoice';
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
And there appears to be some problem with the encoding of created Blob. If I call this endpoint from Postman and select "save response" then "save to a file", I get the correct pdf. When I use the presented code, file seems to be incorrectly encoded (opened with vim has generally similar structure, but different symbols).

In service you can use httpOptions like this:
download() {
const httpOptions = {
responseType: 'blob' as 'json',
};
return this.http.get<any>(
ServerUrl + `/api/getfile`,
httpOptions
);
}
also on you component you can call service and download the pdf like this:
this.api.download().subscribe(
(idata) => {
let blob = new Blob([idata], { type: 'application/pdf'
});
var downloadURL = window.URL.createObjectURL(idata);
var link = document.createElement('a');
link.href = downloadURL;
link.download = 'invoice.pdf';
link.click();
},
async (err) => {
}
);

Related

Download excel file created in node using SheetJS/XLXS [NodeJS] [React]

I'm trying to generate a xlsx file using SheetJS in node. Then in my frontend I have a button to call this route and download the file. Currently I have the following:
// backend code
export function exportExcel(req: Request, res: Response) {
try {
const workbook = utils.book_new();
const fileName = "sample";
const dataSheet = utils.json_to_sheet(sampleData);
utils.book_append_sheet(workbook, dataSheet, fileName.replace("/", ""));
const binaryWorkbook = write(workbook, {
type: "array",
bookType: "xlsx",
});
return res.status(OK).send(binaryWorkbook);
} catch (_error) {
return res.sendStatus(500)
}
}
Then in the front end I have the following:
const handleExcelExport = () => {
const { data } = await axios.get(
`/export-excel`,
{
responseType: "blob",
}
).then(response => {
const blob = new Blob([response], {
type: "application/octet-stream",
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
}
}
// I simply call the above in the onClick handler in a button
<button onClick={handleExcelExport}> Export excel </button>
I can see that a download file appears when I click on the button but I can't open it. MS Excel says that ""File format or file extension is not valid..."
I fixed by changing to the following in the BE:
const binaryWorkbook = write(workbook, {
type: "array",
bookType: "xlsx",
});
and also adding headers per the docs:
res.setHeader(
"Content-Disposition",
'attachment; filename="SheetJSNode.xlsx"'
);
res.setHeader("Content-Type", "application/vnd.ms-excel");
Then in the frontend I changed the response type and content-type to
{
responseType: "arraybuffer",
}
Blob content-type
const blob = new Blob([response], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});

How to trigger a request from javascript to download a file from a backend

I have a webserver that is using flask.
To download a file from the webServer, I have the following code:
#images_api_blueprint.route('/api/v1_2/download_file3', methods=['GET'])
def download_file3():
zipFullFileName1 = './foo.zip'
response1 = send_file(zipFullFileName1, as_attachment=True)
return response1
If I type "http://localhost/api/v1_2/download_file3" in the browser, the file is downloaded - good!
But I need to trigger the download programatically from my client via javascript.
When I click on a button, I reach the code below, which triggers the same url as above,
this.downloadFile3 = function (layer, zipFilename) {
let queryUrl = 'http://localhost/api/v1_2/download_file3';
fetch(queryUrl, {
method: 'get'
})
.then(function(response) {
return response;
})
.catch((err) => {
console.error('error from api/v1_2/download_file3', err);
reject(false);
});
};
But when triggering via javascript, the file is not downloaded.
What am I doing wrong?
Thanks,
Avi
Get a blob and then you can use
function downloadFile(blob, fileName)
{
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
}
or using jquery
$.ajax({
url: requestUrl,
processData: false,
dataType: 'datatype-here'
}).done(function(data) {
var blob = new Blob([data], { type: "image/png; encoding=utf8" });
saveData(blob, 'filename.png');
});

octet-stream on angular - file download not working

I am trying to download a file on a button click, api have been hit successfully am getting 200 response, but file is not being downloaded. It's working on postman.
My code is shown below
/**** click */
downloadAsset() {
this.detailsService.getCsvReport(this.jobId).subscribe(data => {});
}
/**** Service */
getCsvReport(jobId): Observable<Object> {
const header = { Accept: "application/octet-stream" };
let endpoint: string = `${Endpoints.REPORT}jobs/${jobId}/filePath?`;
return this.get(endpoint, header).pipe(
map(report => {
return report.data.parentXml;
})
);
}
<button
class="btn btn-blue-border"
style="float: right;"
(click)="downloadAsset()"
>
Download Report
</button>
Any changes or suggestion's would be appreciated.
You can try like this
getCsvReport(jobId): Observable<Object> {
const header = { Accept: "application/octet-stream" };
let endpoint: string = `${Endpoints.REPORT}jobs/${jobId}/filePath?`;
return this.get(endpoint, header).pipe(
map(report => {
const a = document.createElement('a');
document.body.appendChild(a);
const blob: any = new Blob([report.data.parentXml], { type: 'octet/stream' });
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = data.fileName;
a.click();
window.URL.revokeObjectURL(url);
})
);
}
I think you need to set the response type of your request.
An example with http.post:
this.http.post(url + "/getFile", params, { responseType: "blob" }).subscribe(...)
I hope i can help.

Blank images and pdfs downloaded from Dropbox

I have a problem when downloading files from my dropbox.
While using the type 'text/csv' I can download and view txt files.
Chaning the type to 'image/jpeg' or 'application/pdf' and download the filetype gives me blank file.
Am I on the right track here or is there another way this should be done?
main.service.ts
downloadFile(id) {
const headers = new Headers();
headers.append('Authorization', 'Bearer ' + this.accessToken);
const path = `{"path": "${id}"}`;
headers.append('Dropbox-API-Arg', path);
return this.http.post('https://content.dropboxapi.com/2/files/download',
null, { headers: headers });
}
main.component.ts
downloadFileBlob(data: any, name) {
const blob = new Blob([data], { type: 'image/jpeg' });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
saveFile(id, name) {
this.dropbox.downloadFile(id).subscribe((data: any) => {
this.downloadFileBlob(data._body, name); });
}
Turns out I was going at this the wrong way.
Dropbox github has an example of using sharingGetSharedLinkFile, which works about the same as filesDownload.
Replace sharingGetSharedLinkFile with filesDownload and provide a file path instead of the URL.
Something like this:
function downloadFile() {
var ACCESS_TOKEN = (<HTMLInputElement> document.getElementById('access-
token')).value;
var SHARED_LINK = (<HTMLInputElement> document.getElementById('shared-
link')).value;
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesDownload({path: SHARED_LINK})
.then(function(data) {
var downloadUrl = URL.createObjectURL((<any> data).fileBlob);
var downloadButton = document.createElement('a');
downloadButton.setAttribute('href', downloadUrl);
downloadButton.setAttribute('download', data.name);
downloadButton.setAttribute('class', 'button');
downloadButton.innerText = 'Download: ' + data.name;
document.getElementById('results').appendChild(downloadButton);
});
}

Creating PDF from request response doesn't work with axios but works in native xhr

In order to force download PDF from server I tried to use axios and native xhr object. The reason is that I have to send post request, because I pass too much data to server, so the option with simple link (like site.ru/download-pdf won't work for me).
Even though I finally managed to do this with Xhr, I still don't have a clue why axios way doesn't work.
Here is how I do this with xhr and it works for me:
let xhr = new XMLHttpRequest()
xhr.open('POST', Vue.config.baseUrl + `order-results/${id}/export-pdf`, true)
xhr.setRequestHeader("Authorization", 'Bearer ' + this.token())
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.responseType = 'arraybuffer'
xhr.onload = function(e) {
if (this.status === 200) {
let blob = new Blob([this.response], { type:"application/pdf" })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
}
};
xhr.send("data=" + data);
Here is "axios-way" and I actually get PDF with correct number of pages, but they are all empty:
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'arraybuffer'
}).then((response) => {
let blob = new Blob([response.data], { type:"application/pdf" })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
})
Axios is already configured to send Authorization token.
I put Application/x-www-form-urlencoded in xhr because otherwise I couldn't get data in server side.
Even though xhr works, I'd prefer to use axios since I use it everywhere and I'm just curios what I'm doing wrong. I tried different solutions, and only native xhr did the job.
The following works for me:
axios.post("http://localhost:8080/reports/my-report/",
data,
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/pdf'
}
})
.then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf'); //or any other extension
document.body.appendChild(link);
link.click();
})
.catch((error) => console.log(error));
Let me know if this helps.
Cheers!
For whatever reason the pdf is downloading but any content passed is not appearing resulting in a blank pdf.
I found this code snippet that is similar but results in a pdf with content.
axios({
url: '/pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
there was some feedback stating that it didnt work on IE 11, I have not tested it but a solution was posted using FileSaver.js
axios({
url: '/pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
FileSaver.saveAs(new Blob([response.data]));
});
There is a special responseType: 'blob':
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'blob'
}).then((response) => {
let link = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
})
Or you can use window.open method:
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'blob'
}).then((response) => {
window.open(URL.createObjectURL(response.data));
})
You're getting empty PDF 'cause no data is passed to the server. You can try passing data using data object like this
axios.post(`order-results/${id}/export-pdf`, {
data: {
firstName: 'Fred'
},
responseType: 'arraybuffer'
}).then((response) => {
console.log(response)
let blob = new Blob([response.data], { type: 'application/pdf' } ),
url = window.URL.createObjectURL(blob)
window.open(url); // Mostly the same, I was just experimenting with different approaches, tried link.click, iframe and other solutions
});
By the way I gotta thank you so much for showing me the hint in order to download pdf from response. Thank ya :)
var dates = {
fromDate: 20/5/2017,
toDate: 25/5/2017
}
The way in which I have used is,
axios({
method:'post',
url:'/reports/interval-dates',
responseType:'arraybuffer',
data: dates
})
.then(function(response) {
let blob = new Blob([response.data], { type: 'application/pdf' } );
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'Report.pdf';
link.click();
});

Categories

Resources