I'm messing with a piece of code to download a CSV from server. this is what I'm trying:
downloadCSVTemp(){
let name = 'report.csv';
const response = api.getReportCSV()
.then((res)=>{
const blob = new Blob([res], { type: "data:text/csv;charset=utf-8," });
const blobURL = window.URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.download = name;
anchor.href = blobURL;
anchor.dataset.downloadurl = ["text/csv", anchor.download, anchor.href].join(
":"
);
anchor.click();
});
}
getReportCSV(){
return axios.get("/export/assessments/");
}
I intend to download a csv file from server url by an axios call, But this code is downloading an csv file which can't be opend by the browser & full of garbage data. What's the problem here ?
The res argument contains Axios response object. When creating the blob, you should use res.data:
new Blob([res.data], { type: "data:text/csv;charset=utf-8," });
Related
I can not quite wrap my head around on how to download a PDF from a google spreadsheet PDF Export Weblink. I generated a testing spreadsheet for this case.
I understand that I need to implement encodeURIComponent and/or "Buffer.from" to the blob but however I do it, it only downloads a broken PDF for me.
This is what I currently have in its rawest form. Thank you for your support!
Node JS:
const fetch = require('node-fetch');
var url = "https://docs.google.com/spreadsheets/d/1fLjKASR_g5wsvOjjJi6RclqMVd2o_1On-OfimXtId4E/export?exportFormat=pdf&format=pdf&size=A4&fzr=true&gid=477517973&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&portrait=true&fitw=true&fith=true&top_margin=0.20&bottom_margin=0.20&left_margin=0.20&right_margin=0.20";
let blob = await fetch(url).then(r => r.blob());
// then send blob variable to javascript
Javascript:
function downloadURI(name) {
var uri = 'data:application/pdf;base64,' + blob;
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
downloadURI("test"+".pdf")
I thought that from var uri = 'data:application/pdf;base64,' + blob; in your script, in this case, it is required to convert the downloaded data as the base64. Although I'm not sure about the relationship between the scripts between Node JS: and Javascript:, in your situation, how about the following modification?
From:
let blob = await fetch(url).then(r => r.blob());
To:
let buf = await fetch(url).then((r) => r.arrayBuffer());
const data = Buffer.from(buf).toString("base64");
By this, you can use data as follows.
var uri = 'data:application/pdf;base64,' + data;
Note:
As the additional information, for example, if you want to download your Spreadsheet as a PDF file using only Javascript, you can also use the following script. But, in this case, the Spreadsheet is required to be publicly shared. Please be careful about this.
async function downloadURI(name) {
var url = "https://docs.google.com/spreadsheets/d/1fLjKASR_g5wsvOjjJi6RclqMVd2o_1On-OfimXtId4E/export?exportFormat=pdf&format=pdf&size=A4&fzr=true&gid=477517973&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&portrait=true&fitw=true&fith=true&top_margin=0.20&bottom_margin=0.20&left_margin=0.20&right_margin=0.20";
let blob = await fetch(url).then((r) => r.blob());
var f = new FileReader();
f.readAsDataURL(blob);
f.onload = d => {
var uri = d.target.result;
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
}
downloadURI("test"+".pdf")
I am able to send a single image file to ReactJS. But I have to send multiple image files to ReactJS.
JAXRS code:
#GET
#Path("/download/file1")
#Produces( MediaType.APPLICATION_OCTET_STREAM )
public Response getFile() {
String fileName = DOWNLOAD_FILE_SERVER+"BMI/testcases/Basispath_BMI_0_out.gif";
File file = new File( fileName);
System.out.println("fileName inside getFile = "+fileName);
final String filename = "testcase1.gif";
System.out.println("filename inside getFile = "+filename);
// Create the JAXRS response
// Don't forget to include the filename in 2 HTTP headers:
//
// a) The standard 'Content-Disposition' one, and
// b) The custom 'X-Suggested-Filename'
final Response.ResponseBuilder builder = Response.ok(
file, MediaType.APPLICATION_OCTET_STREAM)
.header("X-Actual-Content-Length", file.length())
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
// All Done.
return builder.build();
}
ReactJS code:
downloadImage = () => {
axios({
url: 'http://localhost:9900/EXAMPLE/rest/myresource/download/file1',
method: 'GET',
responseType: 'blob',
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
var filename = 'Image1.gif'
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch((response) => { // then print response status
console.log("response = ",response);
})
}
Questions:
Is it possible to send multiple image files in the response of JAXRS?
How to receive multiple files in ReactJS GET response?
How to display received files in ReactJS?
Please provide solution to this issue.
The thing is axios calls return files. sometimes xlsx, sometimes plain txt.
In javascript, as soon as I get them, i force download it via blob.
Something like this:
var headers = response.headers;
var blob = new Blob([response.data], {
type: headers['content-type']
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "report.xlsx";
link.click();
As you see, I got something like this: link.download = "report.xlsx" . What I want is to replace xlsx with dynamic mime type so that sometimes it's report.txt and sometimes it's report.xlsx.
How do I do that from content-type?
You can get the file extension using the content type of headers.
Use this Javascript library - node-mime
You just want to pass your headers['content-type'], it will give you the file extension which you need to set for download name.
var ctype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
console.log(mime.getExtension(ctype));
<script src="https://wzrd.in/standalone/mime#latest"></script>
Example: In your case,
var headers = response.headers;
var blob = new Blob([response.data], {
type: headers['content-type']
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "report." + mime.getExtension(headers['content-type']);
link.click();
Incomplete list of MIME types from Mozilla Developers.
What is the backend of your application? I used this in C# (.NET Core) to get the content type of a file then set it as a header in the response:
public string GetContentType (string filePath) {
var contentTypeProvider = new FileExtensionContentTypeProvider();
string contentType;
if( !contentTypeProvider.TryGetContentType( filePath, out contentType ) ) {
contentType = "application/octet-stream";
};
return contentType;
}
Edit: modified OP code to handle content type dynamically:
var headers = response.headers;
var responseType = headers['content-type'];
var fileType = "text/plain";
var fileName = "report.txt";
if ( responseType == "application/octet-stream" ) {
fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
fileName = "report.xlsx";
}
var blob = new Blob([response.data], {
type: fileType
});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
I need to save XLSX file on frontend that im getting from XHR to api.
In api response i got this headers:
Content-Type: application/octet-stream
content-disposition: attachment; filename = OrdersList-253CREATED0.xlsx
And part of response body:
PKõzMdocProps/core.xmlMKÄ0ïý!÷vVd-mQÅ++ÞB:¶Åæ$Úõßí®Å£ÇÉû¼Ã¤\ïåHÞѺA«²$¥Ðí º>6xE×uB[ÜZmÐú -å*Ú{o
'zÜ%!V!yÑVrFÛáâwYDÏ[î9l±Ytôè+ùwe+¥y³ã,hàwÀ߬G+Ý9YȽj¦dÊg.lÄàéîöa^>ó\ ¤uDHy²Â"÷Øà(üÁ~%»üêºÙÐ:KÙ*fYÌ.,-²¼8ËKøÕ?9£¶õe8Kd{ ...
In my code, I tried many options:
1) replace type: "application/octet-stream" to application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
2) creating blob/file without s2ab function like this Blob([binary_string], ...)
let binary_string = response;
// Download using blob:
let ab = s2ab(binary_string),
blob = new Blob(
[ab],
{type: "application/octet-stream"}
);
let downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = 'test-blob.xlsx';
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
// Download using file
let FileSaver = require('file-saver'),
ab = s2ab(binary_string),
file = new File(
[ab],
"test-file.xlsx",
{type: "application/octet-stream"});
FileSaver.saveAs(file);
// s2ab function
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
Why i cant just use iframe, or a[download]? Because authorization header is required.
The file from response is correct, it opens when loading via postman, but when im trying to save it via js from XHR response it always corrupted.
I would be very grateful for the help :)
Im solved the problem.
In this projects im using react, so ofc im used axios for ajax requests.
I think the problem in some axios settings or with axios itself;
Working code example on vanilla js:
var request = new XMLHttpRequest();
request.open('GET', `http://localhost/api/get_xlsx`, true);
request.setRequestHeader('Token', 'user_auth_token_needed_in_my_app');
request.responseType = 'blob';
request.onload = function(e) {
if (this.status === 200) {
var blob = this.response;
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, 'test.xlsx');
}
else{
var downloadLink = window.document.createElement('a');
var contentTypeHeader = request.getResponseHeader("Content-Type");
downloadLink.href = window.URL.createObjectURL(new Blob([blob], {
type: contentTypeHeader }));
downloadLink.download = 'test.xlsx';
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
}
};
request.send();
I have a script to download different type files from server side. The code works for text/xml but when the downloaded pdf file is empty.
let response = this.http.get(this.Url , new Headers({responseType: 'blob'}))
.subscribe(doc => {
if (doc) {
let contentType = doc.headers.get("Content-Type");
let name = doc.headers.get("Content-Disposition").split("=")[1];
let blob = new Blob([doc.text()], {type: contentType});
let a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob);
a.download = name;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
},
error => this.msgService.showError(this.msgs, error));
My server
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Path("-----")
public Response getDocument(#PathParam("documentId") Long documentId) throws Exception {
Document document = ---------------;
return ResponseHelper.createOkResponse(
output -> IOUtils.write(document.documentContent(), output),
document.documentName(),
document.documentType()
);
}
I can see the doc.text() is returning some byte[]. Also tried {responseType: 'arraybuffer'}. can anyone advise how can i display for pdf ?
Thanks