I have a working API call that returns in the response body a string prepared in Bytes format on the Python side that is a zip file. The String looks something like this, but longer:
PK��Q��F���������������/export_file.csv��uX\M�
This is a zip file containing one csv file. In tools such as postman, hitting the same POST endpoint with the same parameters in the body, I can successfully download a valid zip file, unzip the contents, and view the .csv file. In the browser debugger tools, I can see the API endpoint returning a successful response, with the same string above in the body.
Where I have failed at every attempt is on the react side, doing the work necessary to take this string and download the same zip file. Every suggestion I've read on SO and everywhere else has failed me. Here is what some of my failed attempts look like:
(Also note that a successful API call returns a 26kb payload from this example)
export function downloadZipFile(responseBody){
/* Blob Attempts */
// These download a 46kb file. Attempting to open gives "The compressed zip folder is invalid"
// var blob = new Blob([responseBody], {type: "content-type"});
// var blob = new Blob([responseBody], {type: "application/zip"});
// var blob = new Blob([responseBody], {type: "application/zip, application/octet-stream"});
// var blob = new Blob([responseBody], {type: "application/octet-stream"});
// var blob = new Blob([responseBody], {type: "octet/stream"});
var fileName = "export.zip";
saveAs(blob,fileName);
/* Data String Attempts */
// const dataStr = "data:application/zip;" + responseBody; // "Failed - Network Error"
// const dataStr = "data:application/zip, application/octet-stream;" + responseBody; // Downloads 1kb File "The compressed zip folder is invalid"
// const dataStr = "data:application/zip,application/octet-stream;" + responseBody; // Downloads 1kb File "The compressed zip folder is invalid"
// const dataStr = "data:application/octet-stream;" + responseBody; // "Failed - Network Error"
let downloadElement = document.createElement('a');
downloadElement.setAttribute("href", dataStr);
downloadElement.setAttribute("download", "export.zip");
document.body.appendChild(downloadElement);
downloadElement.click();
downloadElement.remove();
}
I've arrived late, but hope to help someone.
It is really important to set responseType as 'arraybuffer' in the api call, like this:
...
export const getZip = async (id) => {
const { data } = await axios.get(
"/sypa-applications/export",
{
id
},
{ responseType: "arraybuffer" }
);
return data;
}
...
Then you can download the ZIP from both ways:
1.- Using file-saver npm dependency:
let blob = new Blob([data], { type: "application/zip" });
saveAs(blob, "fileName.zip");
2.- Using DOM:
const url = window.URL.createObjectURL(new Blob([data], { type: "application/zip" });
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "fileName.zip");
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
I couldn't download the ZIP until I set the responseType param to "arraybuffer" in the GET request.
Best regard,
Alberto.
Did you check this tool? https://gildas-lormeau.github.io/zip.js/
There is an example for unzipping a file using js in the browser. http://gildas-lormeau.github.io/zip.js/demos/demo2.html
It seems that this is what you want. First unzip the file and the use the .csv as wanted
Related
I've got this code:
let file: File = fileList[0];
console.log(file);
var fileReader = new FileReader();
fileReader.onload = (event) => {
this.fileString = fileReader.result as string;
};
fileReader.readAsText(file);
That saves a file's blob as a string. Now I need code that can recover the original blob from the fileString. I'm not seeing any posts that address this already.
Does anyone know how I can recover the original blob?
Currently, I'm trying this code (because the file I'm uploading it a word doc):
var myblob = new Blob([this.fileString], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
console.log(myblob);
saveAs(myblob, "test.docx");
And I'm surprised to see that the original file when console logged is size: 247583 and when I console log in the 2nd section, it's size 433474
I have a saved .PDF file on my system, and I am trying to send the file to the frontend using node/express.
I'm getting the file to send to the frontend as a stream (binary string), but when running some code on the frontend to get the .PDF to download onto the users computer, the .PDF file shows up blank.
Here is my route on the server:
app.post('/someroute', (req, res) => {
let pdfPath = './somepath/where/the/pdf/is'
// if the file does not exist
if (!fs.existsSync(pdfPath)) {
console.log(`The PDF does NOT exist # ${pdfPath}`)
return res.json({ success: false });
}
res.download(pdfPath, (err) => {
if (err) {
console.log('there was error in res.downoad!', err)
} else {
fs.unlink(pdfPath, (err) => {
if (err) {
console.log('there was error in unlinking the pdf file!', err)
} else {
console.log('success!')
}
})
}
})
})
Here is the code on the frontend:
$.post("/someroute", function(data) {
console.log('creating PDF...', data)
var downloadLink = document.createElement('a')
downloadLink.target = '_blank'
downloadLink.download = 'new_pdf_haha.pdf'
var blob = new Blob([data], { type: 'application/pdf' })
var URL = window.URL || window.webkitURL
var downloadUrl = URL.createObjectURL(blob)
// set object URL as the anchor's href
downloadLink.href = downloadUrl
// append the anchor to document body
document.body.append(downloadLink)
// fire a click event on the anchor
downloadLink.click()
// cleanup: remove element and revoke object URL
document.body.removeChild(downloadLink)
URL.revokeObjectURL(downloadUrl)
})
Here is the stream i'm receiving on the frontend:
stream on the frontend
Here is the PDF i'm expecting to be downloaded on the frontend:
Here is what's actually being downloaded:
If anyone can lend any insight or help it would be very much appreciated, thanks!
I think the main reason this isn't working for you is because jQuery doesn't support the 'blob' data type.
I did some research and found an example of how to get this to work with jQuery:
http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
You need to include the jQuery plugin from the blog post then convert your $.post call to a $.ajax call (with method POST) and specify that the transfer data type be 'binary' (to load the plugin).
After including the plugin, change your code to look like this:
$.ajax({
method: "POST",
url: "/someroute",
dataType: 'binary' // USE THE PLUGIN
})
.then(function (data) {
console.log("Got the PDF file!");
// Do with the PDF data as you please.
var downloadLink = document.createElement('a')
downloadLink.target = '_blank'
downloadLink.download = 'new_pdf_haha.pdf'
var blob = new Blob([data], { type: 'application/pdf' })
var URL = window.URL || window.webkitURL
var downloadUrl = URL.createObjectURL(blob)
downloadLink.href = downloadUrl
document.body.append(downloadLink) // THIS LINE ISN'T NECESSARY
downloadLink.click()
document.body.removeChild(downloadLink); // THIS LINE ISN'T NECESSARY
URL.revokeObjectURL(downloadUrl);
})
.catch(function (err) {
console.error("An error occurred.");
console.error(err);
});
There's a full working example for you here:
https://github.com/ashleydavis/pdf-server-example
Note that my server setup is different to yours, that may or may not be an issue for you. I have included example code for streaming and non-streaming PDF file download for comparison - streaming is used by default because I think that's what you wanted.
Also note that it does not appear necessary to add your synthesized link to the document and I have marked those lines as unnecessary.
I should also note that it is probably best to do this kind of thing with HTTP GET rather than HTTP POST. If you did that you could simplify your browser download code to be the following:
var downloadLink = document.createElement('a');
downloadLink.target = '_blank';
downloadLink.download = 'new_pdf_haha.pdf';
downloadLink.href = "someroute";
document.body.append(downloadLink)
downloadLink.click()
document.body.removeChild(downloadLink);
is there a way to force the browser through JavaScript/TypeScript to open the download-window. I'd like to open the download-window because most users are downloading directly to the download folder and I'd like to offer the user the possibility to rename the file and to choose the download folder.
I enable the download like this:
const json = JSON.stringify(data);
const blob = new Blob([json], {type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.getElementById('export');
a.download = 'export.json';
a.href = url;
Full blogpost for the same : Download File in Angular Js2 Application
this two line missing in you code :
var url= window.URL.createObjectURL(b);//add this line
window.open(url);//add this line for download
I suggest try like this :
constructor(private http:Http)
{}
DownloadFile():void
{
this.getFile("http://localhost:1800/api/demo/GetTestFile")
.subscribe(fileData =>
{
let b:any = new Blob([fileData], { type: 'application/zip' });
var url= window.URL.createObjectURL(b);//add this line
window.open(url);//add this line for download
}
);
}
public getFile(path: string):Observable<any>{
let options = new RequestOptions({responseType: ResponseContentType.Blob});
return this.http.get(path, options)
.map((response: Response) => <Blob>response.blob()) ;
}
similar answer by me : Angular JS empty pdf in new window
When i do a post request to a route i have
/generate/image
i get something like: var file =
����JFIF��C��C��� ��
�����+�}Yϭ�F39M>���������>���;��ˋ��uXʽ�w�ڤx\-[2g��k�S���H���m
[�V?[_W����#��v��}6�[��F�F�%����n�...
in the client i do:
var blob = new Blob([file], {type: 'image/png'});
var reader = new FileReader();
reader.onload = function (e) {
$('#result').attr('src', e.target.result);
};
reader.readAsDataURL(blob);
but i get a corrupt image
what can i do?
EDIT:
if i do
img.src = 'data:image/png;base64,' + btoa(file);
i get:
Uncaught InvalidCharacterError: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
Please don't use base64 and wast bandwidth + CPU
Send the image binary as is and handle them correctly with Ajax.
You should not get the result as a string. set xhr responseType to blob or use fetch's blob method.
fetch("/generate/image").then(res => res.blob())
When you have the blob don't use the file reader to turn it to a url.
Use URL.createObjectURL(blob)
At your backend you can do following:
var fs = require('fs');
fs.readFile(path to image from you file, 'base64', function(err, buf){
/* Here you can send your base64 image data to client. Your base64 data is in buf.
I am using socket. You can just send. Read more about readFile function*/
socket.emit('image upload', { image: true, buffer: buf });
});
As my client receives data from socket, I call a function:
socket.on('image upload', function(data){
displayImage(data);
});
var displayImage = function(data){
var URL = 'data:image/jpg;base64,'+data.buffer;
document.querySelector('#img-id').src = URL;
};
The image will then be showed in img tag.
Hope this works for you.
I have a url which has a image. I want to download that image using chrome api. I am developing a chrome app and not extension.
Can anyone please tell me where i am going wrong??
My code:
service('fileService', function($window){
this.saveUserInfo = function(theFilePath) {
// filepath is the url passed from controller{
// Get the directory entry stored (if any).
var fileUrl = "";
var config = {
type: 'saveFile',
suggestedName: 'TheBee.png',
accepts:[{extensions: ['png', 'jpg', 'jpeg']}]
};
chrome.fileSystem.chooseEntry(config, function(writableEntry) {
chrome.fileSystem.getWritableEntry(writableEntry, function(entry1) {
entry1.getFile(theFilePath, {create:true}, function(entry2) {
entry2.createWriter(function(writer) {
var blob = new Blob({type: 'image/png'});
writer.write(blob);
});
});
});
});
});
});
Change
var blob = new Blob({type: 'image/png'});
To
var blob = new Blob([entry1],{type: 'image/png'});
The Blob contructor acceptes blob parts: MSDN=> Blob(blobParts[, options])
You cannot use getFile on entry1 because it is a file itself. You will need to change config.type to "openDirectory"
You also need to add an empty array as the first input to the blob constructor.