Why is ajax not passing through image file? - javascript

For some reason, when I don't use Ajax, the image file in the form being processed comes through just fine, but not when using the Ajax script below.
Can't figure out why...
Note: Not all form fields are image files (there are some text fields).
jQuery.ajax({
method: 'POST',
url: 'actions/listings-add.php',
data: $('#form').serialize(),
dataType:'json',
success: function(msg){
if(parseInt(msg.status)==1)
{
window.location=msg.txt;
}
else if(parseInt(msg.status)==0)
{
error(1,msg.txt);
}
}
});

JSON does not work with "file" inputs, because they need to be transfered with multipart/form-data.
To upload files using AJAX, you can either use FormData to also transfer the file input or if you have a normal rest api that follows a standard endpoint use javascript to base64 encode the image into a string and then transfer it using your ajax request.
To convert the image, you have to use the browsers file api:
// Convert file to base64 string
export const fileToBase64 = (filename, filepath) => {
return new Promise(resolve => {
var file = new File([filename], filepath);
var reader = new FileReader();
// Read file content on file loaded event
reader.onload = function(event) {
resolve(event.target.result);
};
// Convert data to base64
reader.readAsDataURL(file);
});
};
// Example call:
fileToBase64("test.pdf", "../files/test.pdf").then(result = {
console.log(result);
// ##### PUT YOUR AJAX CALL HERE
});

Related

How to send both text and binary data in axios post request?

I would need to find a solution to send via a single axios POST request both of the following:
json structure
binary file (excel file)
How can I achieve this?
let files = event.target.files;
const fileReader = new FileReader();
fileReader.readAsText(files[0], null);
fileReader.onload = () => {
this.fileContent = fileReader.result;
let binaryDataForObject = this.fileContent;
let referenceDataStructure = {
textData: textDataForObject,
binaryData: binaryDataForObject,
referenceDataFileExtension: this.referenceDataFileExtension,
userProvidedDataTypes: this.columnTypes
};
}
this.axios
.post(
"http://url,
referenceDataStructure
)
This works technically but on the java side I couldn't figure out, how to decode the binary data (encoded as a string) so that it is treated as an excel file.
Thank You in advance for any meaningful responses.
Lubos.
With simple POST request you can send only up to 1mb of binary data
To send binary and text in one request you should use FormData
Check out this answer for information
Update 14.12
How I managed to do this in my recent project was using FormData
So firstly you need to get file as a blob:
const fileReader = new FileReader()
// Here we will get the file as binary data
fileReader.onload = () => {
const MB = 1000000;
const Blob = new Blob([fileReader.result], {
// This will set the mimetype of the file
type: fileInputRef.current.files[0].type
});
const BlobName = fileInputRef.current.files[0].name;
if (Blob.size > MB) return new Error('File size is to big');
// Initializing form data and passing the file as a param
const formData = new FormData();
// file - field name, this will help you to read file on backend
// Blob - main data to send
// BlobName - name of the file, default it will be name of your input
formData.append('file', Blob, BlobName);
// Append json data
formData.apped('some-key', someValue)
// then just send it as a body with post request
fetch('/api/submit-some-form-with-file', {
method: 'POST',
body: formData
})
// Handle the rest
.then()
}
fileReader.readAsArrayBuffer(fileInputRef.current.files[0])
You can wrap this example in handle submit function in react and like or use it as is

Converting dataURI to file for upload via REST does not work but normal filefield upload works fine

I have implemented a solution that accepts a single file upload (image for profile) in a Django Rest Framework backend. This route api/people/id/upload_image. Only accepts a parameter with an image. and can be used via HTTP POST.
When uploading via a fileinput field in eg. Postman, the default Django API or via browser fetch() in my Vue.js application is no problem. So it seems as long as it is a default form-upload field it is doing its job.
But in my frond-end (vuejs 3) I am using an image-cropper. Users can upload an image and via the javascript cropper the image can be cropped. This is important for the UI because I need a square image. The cropper uses HTMLCanvasElement.toDataURL() as export format.
And what seemed to be not that difficult gets me stuck for days now. I just can't find a way to convert and POST the cropped image in such a way that is accepted by the upload_image API backend. I am using Fetch() for sending this POST call.
I am not a javascript expert so I get my knowledge via internet and I tried it in several ways; with first creating a BLOB from the dataURI, and by creating a File before feeding it to dataForm and send it as :body in Fetch()
The dataURI seems OK because I am also replacing the cropped image directly in the HTML. And that looks totally fine. The API is responding with an 'HTTP 200 OK'. But the old image is not being replaced.
So my assumption is that there is something wrong with the image send to the API, because via normal fileupload everything works fine. How should I convert this dataURI in a proper way so it can be send and accepted by the API endpoint. And how should the API call look like: headers, body..
this is my last attempt in converting and sending the cropped image: (dataURIimage is OK)
uploadPhoto(context, dataURIimage) {
const blob = dataURItoBlob(dataURIimage);
const resultFile = new File([blob], "picture", {
type: "image/png"
});
const formData = new FormData();
formData.append("image", resultFile);
const headerToken = "Token" + " " + this.getters.getToken;
const url =
"https://workserver-7e6s4.ondigitalocean.app/api/people/" +
this.getters.getProfiel.id +
"/upload_image/";
fetch(url, {
method: "POST",
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': headerToken,
},
body: formData,
})
.then(function(response) {
console.log(response.status)
if (response.ok) {
return response.json();
}
})
.then(function(data) {
console.log(data.image);
})
.catch(function(error) {
alert(error + " " + ":ERROR");
});
},
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
Martijn dekker

How to convert BLOB to image using python

I need to send an image from client to server using blob
I have converted a image to BLOB in jquery (client side) and sending the blob to python flask (server side) the problem is, I can't recreate image from BLOB. I have tried the following code in python but failed to get the image
Jquery code to convert image to blob:
function changeFile() {
var file = this.files[0];
var reader = new FileReader();
reader.addEventListener('load', readFile);
reader.readAsText(file);
}
function readFile(event) {
document.body.textContent = event.target.result;
console.log(event.target.result);
appendFileAndSubmit(event.target.result);
}
function appendFileAndSubmit(imageUrl){
var ImageURL = imageUrl
var data = {
'logo':ImageURL
}
$.ajax({
url: 'http://sdsdss/User/imgBlob',
method: 'POST',
dataType : 'json',
data: JSON.stringify(data),
contentType: 'application/json; charset=utf-8'
}).done(function(response){
var datas = JSON.parse(response);
console.log(datas);
});
}
document.getElementById("inp").addEventListener("change", changeFile);
Python Code: To recreate BLOB to image
function getImage(self):
reqData = json.loads(request.data)
Logo = reqData['logo']
png_recovered = base64.decodestring(Logo)
f = open("temp.png", "w")
f.write(png_recovered)
f.close()
Don't read the file as text, You are dealing with binary data. Best way to transfer binary with json is if you read the file as base64 instead reader.readAsDataURL(file) This will encode all bytes to a web safe base64 string (no slash or plus). Then you have to decode it with python as well.
I discourage you from using json when dealing with file transfer as it will increase the bandwidth with ~3 times as much (not to mention the time it also takes to decode and encode it back and forth) For this I recommend you instead use FormData.
var fd = new FormData()
fd.append('logo', files[0])
$.ajax({
url: 'http://sdsdss/User/imgBlob',
method: 'POST',
data: fd,
// Setting false prevent jQuery from transforming the data
processData: false,
contentType: false
}).then(function(response) {
console.log(JSON.parse(response))
})
or simpler yet, just post the file without any formdata, json or extra fields if they are not necessary.
fetch(uploudUrl, { method 'PUT', body: this.files[0] })

Read downloaded blob from dropbox API using HTTP

Using dropbox you can create a shortcut by dragging and dropping a URL into your Dropbox folder. This will be saved like this:
Using the /2/files/download HTTP API from dropbox will return an XHR response that looks something like this:
How do you parse this response so that you can grab only the URL and make that a clickable link?
Here is what needs to go into an Angular 1 factory. To use this, you would just call the downloadFile function from a controller and provide the path to the file in your dropbox account.
function downloadFile(filePath) {
if (!filePath) {
console.error('Cannot download file because no file was specified.');
return;
}
return $q(function(fulfill, reject) {
$http({
url: 'https://content.dropboxapi.com/2/files/download',
method: 'POST',
headers: {
'Authorization': 'Bearer {{access-token-goes-here}}',
'Dropbox-API-Arg': `{"path": "${filePath}"}`
},
responseType: 'blob'
}).then(
results => {
// data received from dropbox is binary data saved as a blob
// The FileReader object lets web applications asynchronously read the contents of files
// https://developer.mozilla.org/en-US/docs/Web/API/FileReader
var fileReader = new FileReader();
// function will run after successfully reading the file
fileReader.onload = function() {
var string = this.result; // store the file contents
string = encodeURI(string); // get rid of the paragraph return characters
var endPosition = string.indexOf('%0D%0A', 32); // find the end of the URL, startPosition is 32
var actualURL = string.substring(32, endPosition); // grab only the characters between start and end positions
fulfill(actualURL);
};
fileReader.readAsText(results.data);
},
error => reject(error));
});
}

error in uploading file data via jQuery Ajax POST request

I am receiving an error trying to upload large than 50kB file via jQuery Ajax POST request.
I am sending the request to OData service ( ASP.Net MVC application)
The error I am receiving in browser console is " 413 Request Entity Too Large "
Below is the code I am using to upload
var fileData =
{
fileBinaryData: encodedData //file data in encoded format ( 64 bit),
Description: "my first file"
};
fileData = JSON.stringify(fileData);
$.ajax({
url: // some odata url ,
type: "POST",
data: fileData,
success: function (res) {
// do something
},
contentType: "application/json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
});
a) Is code above the correct way to upload file data via jQuery ajax to a service
b) I have modified my web.config to accept large requests.
c) I do not want to use plugin's like uploadify etc
EDIT 1:
I used javascripts' FileReader() to read the file.
var reader = new FileReader();
//then applied reader.onloadend method etc
if (file.webkitSlice) {
var blob = file.slice(start, stop + 1);
} else if (file.mozSlice) {
var blob = file.mozSlice(start, stop + 1);
}
reader.readAsBinaryString(blob);
Finally settled with using jQuery fileUpload plugin

Categories