Creating Blob object from raw file downloaded from server with $http. - javascript

On server there is url with files stored.
Url is http://website.com/abc
I do $http get on this url.
$http.get(url, { responseType: "arraybuffer" });
I want to create Blob object from this. I am sure that object is of type png, because it had this extension before upload and it shows properly.
new Blob(result.data, {type: "image/png"});
I get message:
Failed to construct 'Blob': The 1st argument is neither an array, nor does it have indexed properties.
Response from server http://website.com/abc GET in developer console looks like:
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 60
ÿÛC

 ' .)10.)-,3:J>36F7,-#WAFLNRSR2>ZaZP`JQROÿÛC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOÿÂÒ"ÿÄÿÄÿÚæå2ag\Ý#úDê3[Zdfc5±Ô¢¬æ)K<`¤l2¸ÊánYR±aA`Í%RÈfbz!¤tÞÑ-µd7ZªÀ[hz¨f¥>©cAV¬{3á R³F0 W>~c³"ðÈìøÖ²ÇBÙ³±+
½ò9tµ°õ
I tried to set Blob type to application/octet-stream and also do $http.get without specified responseType.
How can I create a proper Blob file?
I need Blob File, to create File object which is an entry data to implemented logic to display files in slideshow with modals. I have implemented logic for files of type File, which were created by input forms - implementation was done for a need before uploading to server. Now it turns out that server doesn't return same files to me, but return only urls of files, which created an idea to convert from url to File in order to dont repeat in that logic.

Try
$http.get(url, { responseType: "blob" });
or
// missing `[]` at `js` at Question
new Blob([result.data], {type: "image/png"});
Note XMLHttpRequest responseType could also be set to "blob", see How to build PDF file from binary string returned from a web-service using javascript

Related

Does there exist a 'good-practice' way to send files without relying on FormData?

I'm currently working on an app with a React Native front-end and Node.js/Express backend. I am perfectly able to upload files using FormData with Content-Type multipart/form-data. The problem I have is that when using FormData, any other data that you wish to send in the body of the request is necessarily converted to a string. This isn't the case when one simply sends a JS object as the body of the request (as long you parse it on the backend of course). I wish to know if there is a good-practice way to send a file/files alongside JSON in a request, without losing the typings of said JSON?
Thanks
Add your data as JSON in a field of the FormData:
const data = {
foo: ["bar", 1]
};
const file = new File(["some content"], "myfile.txt");
const formdata = new FormData();
formdata.append("file", file);
// Send as JSON
formdata.append("data", JSON.stringify(data));
const req = new Request("./", { method: "POST", body: formdata });
// simulate server side getting the response
req.formData().then( (fd) => {
const received_file = fd.get("file");
// parse JSON
const received_data = JSON.parse(fd.get("data"));
console.log({ received_file, received_data });
});
When you insist on sending the image along with other data inside the JSON, then AFAIK your only option is to convert the image to some data type which can be transmitted via JSON.
The most obvious choice would be a string, and what is usually used here is the base64 encoding. It is, however, not very efficient and can cause lag.
What is sometimes done to stay within the JSON domain but still being able to upload images is to create two endpoints. One for the JSON data. One for the image upload in a binary format.

PDF from PUT in new window via Blob URI

I have an API endpoint which on a PUT serves a PDF with Content-Type "application/pdf" (you might ask "why a PUT and not a GET?" and the answer to that is "it’s complicated and I can’t change it").
I want to (client side), request that PDF and display the result in a window.open() call (ie display the PDF in a new window). Previously I used a data URI to do this, ie:
window.open('data:application/pdf,<the data payload from the response>');
but in Chrome 60 this no longer works (you can’t use a data URI in a window.open, see https://bugs.chromium.org/p/chromium/issues/detail?id=751135 ).
I have now changed the client side code to do a fetch() of the same endpoint, create a blob from the response, call URL.createObjectURL() on the blob to get a url, and pass that url to the window.open() call. Ie I have something like:
fetch('http://somedomain.com/rest/getMyPdf', {
method: 'PUT',
... some headers & the body ...
}).then(function(response) {
return response.blob();
}).then(function(blob) {
window.open(URL.createObjectURL(blob));
});
This works in Firefox (I get a PDF in a new window), but in Chrome you just see the raw ASCII of the PDF contents (ie %PDF-1.3.....).
I’m guessing this is some sort of content-type issue, ie if I could set the content type on the url, then Chrome would interpret the response as a PDF. Any suggestions on how to do that?
Try
var data = response.arraybuffer();
Then create a Blob from there with the right content type
var = new Blob(data, 'application/pdf');

How to send file details to back end using angularjs?

Hi I am developing web application in angularjs. I am developing file upload module. I have below array with file details.
//below code to get array of files
$scope.showPicker=function()
{
var client = filestack.init('AGeDIRvVZTRWgtmFbfGuZz');
client.pick({
}).then(function (result) {
arrMakes.push(result.filesUploaded);
});
}
In the above image i shown my array. I have three files.
Below is my angular code to send details to api.
var files = new FormData();
angular.forEach(arrMakes, function (value, index) {
console.log(value,index);
files.append(index, value);
files.append('data', angular.toJson(index).replace(/['"]+/g, ''));
});
return $http.post(this.uploadUrl, files, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined,
}
})
The problem is i am not receiving file in server side. Below line gives me 0 files in server.
System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;
May i know am i sending correct data to server? Can someone help me to fix this? Any help would be greatly appreciated. Thank you.
You are not uploading any files to the server, only strings.
You can't append objects to a FormData. appart from Blob & File objects See what will happen:
fd = new FormData
fd.append(2, {foo: 'bar'})
fd.append('data', 5)
new Response(fd).text().then(console.log)
// you get [object Object]
Why do you stringify the index in "data"? It will be casted to string automatically. And what is there that you have to replace?
If i where you i would just simple send the hole arrMakes to the server and download all the files from the url on the backend, otherwise the client has to download and then upload them to the server and wasting bandwidth and time.
beside, you don't need angulars forEach loop, arrays has that method built in
arrMakes.forEach(function (value, index) {
...
})
You won't even have to use any loop if you just pass the arrMarks to the server

python - send pdf as bytes in web services

I use to build a web service that response with application-json mime type.
But now I want to response a PDF as bytes, so I assume that I have to change mime type.
I will use routing but I could use flask-restful too.
The following code show the structure but I don't know how covert pdf to bytes and then send it.
#app.route('/pdf/myfile')
def pdf():
data = open("myfile.pdf", "rb").read()
# make a reponse with those bytes
return response
In the client side (angular.js) I will have this:
$http.get('/pdf/myfile', null, { responseType: 'arraybuffer' })
.success(function (data) {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
});
You can use send_file or send_from_directory:
from flask import send_from_directory
#app.route('/pdf/myfile')
def pdf():
return send_from_directory('/dir/of/pdf', 'my.pdf')
By default this will send the file inline and browsers will probably render the PDF itself. If you set as_attachment=True the file will be presented as an attachment, and the browser will throw up a "save as" dialog box.
send_file gives you more control over things such as mime types and caching. The defaults should work well.

Google Drive resumable upload with javascript

I'm trying to upload files to Google Drive using Google APIs Client Library for JavaScript and resumable upload type.
I authenticate and get the upload URI successfully, but I ran into problems while sending the actual data. If the file contains only ASCII characters, the file is sent successfully to Drive, but in case of special characters (åäö) or binary file (such as PNG) the file gets corrupted. My guess would be that somewhere in the process the file is encoded to unicode in client side.
If I use "btoa()" to encode the raw data to base64 and add header "Content-Encoding: base64" to the data sending request, the file uploads fine. Using this method however increases the overhead for 33%, which is quite a lot when the planned upload size of files is 100MB to 1GB.
Here are some code examples:
Getting the resumable upload URI:
// Authentication is already done
var request = gapi.client.request({
"path": DRIVE_API_PATH, // "/upload/drive/v2/files"
"method": "POST",
"params": {
"uploadType": "resumable"
},
"headers": {
"X-Upload-Content-Type": self.file.type,
//"X-Upload-Content-Length": self.file.size
// If this is uncommented, the upload fails because the file size is
// different (corrupted file). Manually setting to the corrupted file
// size doesn't give 400 Bad Request.
},
"body": {
// self.file is the file object from <input type="file">
"title": self.file.name,
"mimeType": self.file.type,
"Content-Lenght": self.file.size,
}
});
Sending the whole file in one go:
// I read the file using FileReader and readAsBinaryString
// body is the reader.result (or btoa(reader.result))
// and this code is ran after the file has been read
var request = gapi.client.request({
"path": self.resumableUrl, // URI got from previous request
"method": "PUT",
"headers": {
//"Content-Encoding": "base64", // Uploading with base64 works
"Content-Type": self.file.type
},
"body": body
});
Am I missing something? Is it possible to upload file in binary stream? I am new to uploading files in HTML and Javascript and I haven't found any examples using Google Javascript library with resumable upload. There is similar question in SO with no answers.
Blob types are a hot topic for XMLHttpRequest implementations and they are not truly mature. I'd recommend you to stick with base64 encoding. Google's JavaScript client lib doesn't support resumable uploads because it's very unlikely that a client side browser app uploads very large files directly to Google Drive.
What works
To upload a binary blob, use github/googleapi's cors-upload-sample or use my gist fork, UploaderForGoogleDrive, which will grab access_token out of the gapi client for you.
Here is an ugly mixture of Promise and callback code that works for me. As a prerequisite, gapi,UploaderForGoogleDrive, JSZip need to be loaded via <script> tags. The snippet also omits gapi initialization and the API secrets, which are also necessary.
function bigCSV(){ // makes a string for a 300k row CSV file
const rows = new Array(300*1000).fill('').map((v,j)=>{
return [j,2*j,j*j,Math.random(),Math.random()].join(',');
});
return rows.join("\n");
}
function bigZip(){ // makes a ZIP file blob, about 8MB
const zip = new window.JSZip();
zip.folder("A").file("big.csv", bigCSV());
return zip.generateAsync({type:"blob", compression:"DEFLATE"});
// returns Promise<blob>
}
function upload2(zipcontent){
'use strict';
const parent = 'root';
const spaces = 'drive';
const metadata = {
name: 'testUpload2H.zip',
mimeType: 'application/zip',
parents: [parent]
};
const uploader = new window.UploaderForGoogleDrive({
file: zipcontent,
metadata: metadata,
params: {
spaces,
fields: 'id,name,mimeType,md5Checksum,size'
},
onProgress: function(x){
console.log("upload progress:",Math.floor(100*x.loaded/x.total));
},
onComplete: function(x){
if (typeof(x)==='string') x = JSON.parse(x);
// do something with the file metadata in x
console.log("upload complete: ");
},
onError: function(e){ console.log("upload error: ",e); }
});
uploader.upload();
}
function uploadZipFile(){
'use strict';
(bigZip()
.then(upload2)
);
}
What doesn't work
As of Nov 2017, uploading a binary blob with the gapi.client.request call is not going to work, because of an issue where gapi removes the PUT payload
I've also tried using base64 with gapi, which works. but deposits base64 files, not true binaries; and the fetch API in cors mode, which half-worked but produced CORS-related errors and response hiding, at least for me.

Categories

Resources