Problem in Creating Zip file with JavaScript - javascript

I have requirement in my project with which when user select multiple file to download, we need to zip them and then make them to download. We have tested that the Struts2 action is listing all the file correctly and passing them to the UI. We've verified that the files are list on to UI correctly but when the blob statement executed, it made the zip file corrupted.
Here is the my code snippet.
Can anyone please help here?
Code:
$.ajax({
url: url,
data: data,
type: "POST",
async: true,
success: function (data) {
var binaryData = [];
binaryData.push(data);
var link=document.createElement('a');
link.href =window.URL.createObjectURL(**new Blob(binaryData, {type: "application/zip"**}));
link.download = "User Reports Data Files.zip"
link.click();
},
error: function (request, status, error) {
}
});

Two answers for you:
I don't think you can reliably download binary data with jQuery's ajax function (but I could be mistaken). If you want to download binary, use fetch, which has support for reading the response as a BLOB built in.
It would be simpler to have a zero-height iframe on your page with name="download-target" and then have a form target="download-target method="post" and submit that instead of using ajax. Be sure the response includes a Content-Disposition header, for instance:
Content-Disposition: attachment; filename="User Reports Data Files.zip"
#2 is simpler and lets the browser handle the download in its normal, thoroughly-tested way.
But here's a sketch of #1:
fetch(url, {
method: "POST",
body: data
})
.then(response => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
return response.blob();
});
.then(blob => {
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = "User Reports Data Files.zip"
link.style.display = "none"; // Firefox wants this
document.body.appendChild(link); // ""
link.click();
setTimeout(() => { // ""
document.body.removeChild(link); // ""
}, 10000); // ""
})
.catch(error => {
// Handle/report the error
});

Related

How to download remote image then upload image as an image file for form submission?

There are similar questions like this, this, this, and this, but none help.
In Node, the goal is to use the axios module to download an image from Twitter then upload this image as an image file as part of a form submission.
This code downloads the Twitter image, but the uploaded binary image is corrupted when it reaches the server (also our server).
The image must be uploaded in binary.
A form is required because other fields are also submitted with the binary image. These other form fields were removed to simplify the code sample.
const axios = require('axios');
const FormData = require('form-data');
let response = await axios.get('https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png', {
responseType: 'arraybuffer'
});
let imageBuffer = Buffer.from(response.data, 'binary');
let formData = new FormData();
formData.append('image', imageBuffer);
try {
let response = await axios({
method: 'post',
url: serverUrl,
data: formData,
});
// Do stuff with response.data
} catch (error) {
console.log(error)
}
You should pass the headers to the axios call using formData.getHeaders() to send a Content-Type header of multipart/form-data. Without it, a Content-Type header of application/x-www-form-urlencoded is sent. You could pass a responseType of stream to the axios call that downloads the image and add the stream to the form data.
You can also use axios.post to simplify the method call.
const url = 'https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png'
const { data: stream } = await axios.get(url, {
responseType: 'stream',
})
const formData = new FormData()
formData.append('image', stream)
try {
const { data } = await axios.post('http://httpbin.org/post', formData, {
headers: formData.getHeaders(),
})
console.log(data)
} catch (error) {
// handle error
}
You can use the fetch API to fetch the image as a blob object and append it to form data. Then simply upload it to its destination using Axios, ajax, or the fetch API:
const mediaUrl = "https://pbs.twimg.com/media/EyGoZkzVoAEpgp9.png"
fetch(mediaUrl)
.then((response) => response.blob())
.then((blob) => {
// you can also check the mime type before uploading to your server
if (!['image/jpeg', 'image/gif', 'image/png'].includes(blob?.type)) {
throw new Error('Invalid image');
}
// append to form data
const formData = new FormData();
formData.append('image', blob);
// upload file to server
uploadFile(formData);
})
.catch((error) => {
console.log('Invalid image')
});

File is not showing local language after downloading

I have an application which is developed with node.js and hosted on heroku. We are generating a pdf on the node.js server and sending the stream to frontend, so that the users can download the file.
When i am trying it on the localhost, i am able to see proper content in the file. But when i host the node.js code on heroku and try the same, the file is not showing local language(telugu, an indian language) in the pdf. Below is the screenshot of the file i am getting.
The below code is the frontend code which will hit the server api and get the file content from server
const response = await axios.post(
'/reports/pdf',
{ tests: this.tests },
{ responseType: 'blob' },
);
window.console.log(response);
if (response) {
this.createAndDownloadBlobFile(response, 'tests');
}
The below code is to download the file. This function is called in the above code after getting the response.
createAndDownloadBlobFile(body, filename, extension = 'pdf') {
const blob = new Blob([body]);
const fileName = `${filename}.${extension}`;
if (navigator.msSaveBlob) {
// IE 10+
navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a');
// Browsers that support HTML5 download attribute
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', fileName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
},
The node.js code is as below
return new Promise((resolve, reject) => {
pdf
.create(document, options)
.then((res) => {
var content = fs.readFileSync(path.resolve(__dirname, '../utils/output.pdf'));
resolve(content);
})
.catch((error) => {
reject(error);
});
});
I tried few different ways by changing the response format to base64 and changing the data format. But still no use. Any help would be really appreciated.

How download Excel file in Vue.js application correctly?

I'm struggling to download an Excel file in xlsx format in my Vue.js application. My Vue.js application make post request to the Node.js application which download that Excel file from remote SFTP server. Backend application works without any problems.
In Vue.js application I use next code:
axios.post(config.backendHost + '/excel', {
file_name: fileName
}).then((response) => {
const url = URL.createObjectURL(new Blob([response.data], {
type: 'application/vnd.ms-excel'
}))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
});
After downloading file by browser, file opens automatically and I am experiencing an error that looks like this:
We found a problem with some content .xlsx. Do you want us to try and recover as much as we can?
You need to add the response type as a third argument in your post call
{
responseType: 'blob'
}
Your final code like that
axios.post(config.backendHost + '/excel', {
file_name: fileName
}, {
responseType: 'blob'
}).then((response) => {
const url = URL.createObjectURL(new Blob([response.data], {
type: 'application/vnd.ms-excel'
}))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
});
Or you can use the library FileSaver.js to save your file
import FileSaver from 'file-saver'
axios.post(config.backendHost + '/excel', {
file_name: fileName
}, {
responseType: 'blob'
}).then((response) => {
// response.data is a blob type
FileSaver.saveAs(response.data, fileName);
});
my case worked:
axios.get(`/api/v1/companies/${companyId}/export`, {
responseType: 'blob',
}).then((response) => {
const url = URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute(
'download',
`${companyId}-${new Date().toLocaleDateString()}.xlsx`
)
document.body.appendChild(link)
link.click()
})

Download PDF from http response with Axios

I am working on a Vue application with a Laravel back-end API. After clicking on a link I would like to do a call to the server to download a certain file (most of the time a PDF file). When I do a get request with axios I get a PDF in return, in the body of the response. I would like to download that file directly.
To give you a better view of how the response is looking like:
(note: I know a real text response is better than an image but I don't see any way to return that because of the length of the actual PDF content..)
Is there any way of downloading that file with JavaScript or something? It has to be specific a direct download without clicking on the button again.
Code
// This method gets called when clicking on a link
downloadFile(id) {
const specificationId = this.$route.params.specificationId;
axios
.get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${id}/download`, {
headers: this.headers,
})
.then(response => {
console.log(response);
// Direct download the file here..
})
.catch(error => console.log(error));
},
As #Sandip Nirmal suggested I've used downloadjs and that worked out pretty good! Had to make a few adjustments to my code but in the end it worked out.
My new code
// npm i downloadjs
import download from 'downloadjs'
// method
downloadFile(file) {
const specificationId = this.$route.params.specificationId;
axios
.get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${file.id}/download`, {
headers: this.headers,
responseType: 'blob', // had to add this one here
})
.then(response => {
const content = response.headers['content-type'];
download(response.data, file.file_name, content)
})
.catch(error => console.log(error));
},
You should use 'responseType' option. For example:
axios.get(
url,
{responseType: 'blob'} // !!!
).then((response) => {
window.open(URL.createObjectURL(response.data));
})
You have 2 options for this. If you want to do it from server and if you are using Node.js as a backend. You can do it easily using res.download method of express. You can follow this answer for that Download a file from NodeJS Server using Express.
But if you want to handle it from client then there are few options since you can't use axios, XHR, fetch to download file directly. You can either use download.js or write your own code in following way.
return axios({
url: '/download', // download url
method: 'get',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
mode: 'no-cors'
}
})
.then(response => response.blob())
.then(blob => {
var url = window.URL.createObjectURL(blob)
var a = document.createElement('a')
a.href = url
a.download = fileName
a.click()
a.remove()
setTimeout(() => window.URL.revokeObjectURL(url), 100)
})
Since response returned from server is in json format you need to convert it into ObjectURL and set it to anchor tag.
If you sneak inside download.js code you will find same implementation.
2022 answer: using node.js, fs.promises and async/await
The key is using responseType: 'stream' per the Axios docs.
import axios from 'axios';
import { writeFile } from 'fs/promises';
const downloadFile = async () => {
const response = await axios.get('https://someurl', {
params: {
// ...
},
// See https://axios-http.com/docs/api_intro
responseType: 'stream',
});
const pdfContents = response.data;
await writeFile('file.pdf', pdfContents);
};
You can do it like this
download(filename) {
fetch(url , { headers })
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(uril => {
var link = document.createElement("a");
link.href = uril;
link.download = filename + ".csv";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
here I want to download a CSV file, So I add .csv to the filename.
const downloadPDF = (id, fileName) => {
axios({
method: 'get',
url: `https://api.example.com/pdf/invoice/${id}`,
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token'),
'Content-Type': 'application/json'
},
responseType: 'blob'
}).then(function (response) {
const a = document.createElement('a');
a.href = window.URL.createObjectURL(response.data);
a.download = `${fileName}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
});
}

Download zip folder with REST request in javascript. React.js

I am sending request to download zip folder from server, which is sending me below response - (Zip folder in bytes)
PK�s�H test.txt~���T*-N-R�R*I-.Q���PK�/[�PK�s�Htest.txt���T*-N- R�R*I-.Q���PK�/[�PK�s�H�/[� test.txt~PK�s�H�/[�Ltest.txtPKm�
In react I have written below function to download the zip folder.I am getting error while extracting zip folder.
downloadUtmFile: function() {
function download(text, name, type) {
var a = document.createElement("a");
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
a.click();
}
DashboardStore.downloadFile(API_ENDPOINT.utmFileDownload).then(function(result) {
download(result,'', 'application/zip');
}.bind(this), function(error) {
this.setState({
message: error
});
}.bind(this));
},
I am using Blob and passing it type as "application/zip"
While extracting the zip folder it is throwing me error.
I think this is the header's problem. Need to add the following thing in the request header,
{
"content-type": "application/zip",
responseType: "blob",
}

Categories