Downloading a zip file from a byte array - javascript

I have an api which sends a zip file as a byte array (not the byte arrays of the individual files, but the zipped file on the whole). When I trigger the api in postman, i get random characters (as shown below).
When I download this response (as option in postman: send to a file and download) in a zip file, I am able to unzip it and extract the actual files. My goal is to achieve the same thing in angular and typescript.
I have tried to convert the response to a blob and download it, as suggested in multiple places online, including this question. So I did something like
const blob = new Blob([response], { type: 'application/zip' });
const url = window.URL.createObjectURL(blob);
window.open(url);
But the resultant zip file I download says 'unable to open: empty archive'. I am not sure what I am missing here. I tried converting the response to arrayBuffer (using this) first before applying the steps as well, as that was suggested in another place online. But that hasn't been of use either.
Can someone please help me understand what I'm doing wrong. Thanks
I am calling the API in a js file:
function downloadAzureRT(params) {
return $http({
method: 'GET',
url: API.public('protectionSources/downloadArtFile'),
params: params || {},
}).then(function downloadAwsARTResp(resp){
return resp.data || {};
});
}
And then calling this function in a ts file.
downloadART() {
this.ajsPubSourceService.downloadAzureRT({
filePath: ART_FILE_PATH,
fileName: ART_FILE_NAME,
})
.then((response) => {
const blob = new Blob([response], { type: 'application/zip' });
const url = window.URL.createObjectURL(blob);
window.open(url);
}

Related

Why my generated docx in javascript from a blob is filled with [Object Object]?

I'm sending data to my Django backend through a POST request, the server then creates a docx using this data and sends it back to me where I'm trying to download it using the following code :
axios.post(route, data).then((res) => {
const filename = "report.docx"
var blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
var link = document.createElement('a');
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
link.href = downloadUrl;
link.style = "display: none";
link.download = filename;
document.body.appendChild(link)
link.click()
link.remove()
});
The download of the file works but when I open it, it only contains [Object Object], what am I doing wrong here ? I checked the backend and the document is properly created as it has the right content when I'm saving it when it's generated in the server so it's either that i'm sending it badly or creating the file in the frontend badly.
Here is how I send it from the backend :
#Generating the doc properly before this...
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
report_filename = 'graph-report-'+now.strftime('%Y-%m-%d_%H-%M-%S')+'.docx'
response['Content-Disposition'] = 'attachment; filename=%s'%(report_filename)
document.save(response)
return response
Thanks for helping me.
With Axios, the res in axios.post(route, data).then((res) => is a response object.
The returned data is found in res.data.
Do console.log(res.data) to see that it truly is the binary data you expect.
Do new Blob([res.data], ... to use that data to get the blob. (If it already is a blob courtesy of Axios, you don't necessarily need to bother.)
(As an aside, you don't really need to use fetch() and createObjectURL for this at all since you're forming a download-like binary response; it would be enough to just have the browser POST your desired data e.g. as a form to the endpoint; it would download the response just the same.)

How to download file in memory and then upload it to somewhere else

I would like to do create a tempermonkey script that would download a file on a site without bothering the user with saving it on the disk. So the file would be stored in a variable, which the script would be able to use to upload that file to my remote server.
Is it possible to do in browser javascript?
Diagram:
One option would be to download the file as a blob using fetch:
async function upload() {
const res = await fetch('https://example.com/download-endpoint')
const blob = await res.blob()
fetch('https://example.com/upload-endpoint', {
method: 'POST',
headers: {
'Content-Type': blob.type
},
body: blob
})
}

Blob from PDF File

I receive a PDF using Angular Http from an external API with using Content Type: application/pdf. So a simple Get Request, nothing fancy.
Now I need to convert this into a Blob object. However it doesn't seem to work.
How can I accomplish this in JavaScript?
Somehow directly saying let blobFile = new Blob(result) or let blobFile = new Blob([result]) doesn't seem to work.
You should be able to do the conversion when you do the request if the Content-type is application/pdf:
yourServiceMethod(): Promise<Blob> {
return this.httpClient.get(your-url, { responseType: 'blob' }).toPromise();
}
from there, you can use a utility like file-saver to complete the download process to the client's machine:
import * as FileSaver from 'file-saver';
onDownload(): void {
this.yourService.yourServiceMethod().then(file => {
FileSaver.saveAs(file, fileName);
});
}

Dealing with encoding in Flask file uploads/downloads

I have a react client that takes in user input as a file and sends it to my remote Flask server for storage. I send the file in the form of a Werkzeug FileStorage object and in the remote server I store it with file.save(path). In the react client I'm trying to build a way to download the file from the server, however I'm running into problems. Currently my program is working for downloading .txt files. I'm able to do this though a fetch javascript request:
fetch(FETCH_URL, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {
var a = response.body.getReader();
a.read().then(({ done, value }) => {
saveAsFile(new TextDecoder("utf-8").decode(value), 'filename.txt');
}
);
});
function saveAsFile(text, filename) {
const type = 'application/text'; // modify or get it from response
const blob = new Blob([text], {type});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
}
Thanks to some help I got in this post: Download file in react client from flask remote server
I know this code is specifically made to work only with .txt files based on the type being passed in to Blob, but the front end is not the real problem.
The real problem is in my remote flask server, the following code is what is called in the flask server:
with open(filename, 'r') as f:
contents = f.read()
return contents
I tried returning the file itself but the server gives an error:
"ValueError: I/O operation on closed file."
So I decided to return the contents of the file as shown above.
The problem arises when I try to get a file for example "download.jpeg". Reading the file gives the following error:
"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte"
From what I understand Flask works exclusively with 'utf-8' and I assume this means the file in the server is on 'utf-8' encoded.
Does anyone have a suggestion or guidance on a solution or a workaround maybe a way to change the files encoding when I save it on the server or something else that could help me with what I'm trying to do?
Fetch's Response has blob() to convert the response directly to blob, so you don't have to read the stream, you don't have to find out it's content type or anything. Just try the below solution.
fetch(FETCH_URL, {
method: 'POST',
body: data,
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {
response.blob().then((blob) => {
saveBlob(blob, 'filename');
});
});
function saveBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
}
Try this: make sure to install axios. Also you probably won't have to deal with content type like above said. Obviously changing the method type to POST and bring ur data in.
axios(FETCH_URL, {
method: 'GET',
responseType: 'blob', // important
}).then((response) => { //Creates an <a> tag hyperlink that links the excel sheet Blob object to a url for downloading.
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${Date.now()}.xlsx`); //set the attribute of the <a> link tag to be downloadable when clicked and name the sheet based on the date and time right now.
document.body.appendChild(link);
link.click(); //programmatically click the link so the user doesn't have to
document.body.removeChild(link);
URL.revokeObjectURL(url); //important for optimization and preventing memory leak even though link element has already been removed.
});

Upload a javascript generated PDF file to server

Please note I am uploading a file generated at runtime, NOT a user submitted file. This is where my problem lies, taking that file and sending it along has proven itself to be truly a challenge.
I'm using PDFMake to generate a pdf file. It took me A LONG time to get this code working, tl;dr of it is I convert the pdf doc info to a buffer, make a new File object with that buffer, attach that file object to a formdata object, and send it to my server.
Here is the code:
var pdfGen = pdfMake.createPdf(docDef);
pdfGen.getBuffer(function(buffer){
var pdf = new File(buffer, "testpdf.pdf", {type: "application/pdf"});
var data = new FormData();
data.append('upload', pdf);
data.append('content-type', 'application/pdf');
$.ajax({
method: "POST",
url: "/index.cfm?action=admin:service.upload_pdf",
data: data,
processData: false,
contentType: false,
success: function(msg){
console.log(msg);
},
error: function(msg){
console.log(msg);
}
})
})
The problem is that the file I get on my server isn't a valid PDF. The application type is listed as application/octet-stream. The function I'm pushing the File object to SHOULD be rejecting everything except pdf's, so I'm not sure where the error is exactly.
I've been at this for two days now and I'm at a loss so any help is GREATLY appreciated.
Have you tried converting your generated PDF into Base64 and then sending the result to your server?
Here's what I mean:
var pdfGen = pdfMake.createPdf(docDef);
pdfGen.getBase64((data) => {
PostToServer(data);
});
Source: https://github.com/bpampuch/pdfmake

Categories

Resources