How do I submit complex Json object along with a file upload?
I can do a simple json object successfully, only fails with a complex json:
e.g. [file] + { simple: object } -- okay
e.g. [file] + {some: {complex: 'asdf'}, object:['str1','str2']} -- fails
//here is the simple json data
var params = {simple: 'jsonData'};
//here is the header to enable json stuff
var headers = {
'Content-Type': 'application/json',
'Accept': 'application/json, text/javascript, */*',
'dataType': 'json'
};
//assume we have some files in that html form
var files = fi.button.fileInputEl.dom.files;
form.submit({
url: '/some/api',
waitMsg: 'Uploading your file...',
headers: headers,
params: params,
success: function(a, b) {
//done...
}
});
The code above fails when params is a complex Json object with more than one layer. I am using ExtJs, for those who uses JQuery I guess it is html form so my question would be the same across different js libs.
When doing file uploading, Ext does a form post to a hidden iframe, so you need to parse the data as such.
Related
I read all over but couldn't find the answer.
When I use FormData(), it returns status 404 bad request.
However, if I pass the data (hardcoded) as in const requestBody (example below), it works perfectly.
This is my code:
var formData = new FormData();
formData.append("nickname", "johxns");
formData.append("password", "john_password");
formData.append("email", "john#server.com");
// If I do it this way, and assign this to body inside fetch, it works perfectly
// const requestBody = '{"nickname": "johxns","password":"john_password","email":"john#server.com"}';
fetch("http://localhost:5000/create_user", {
// if instead of formData, I assign requestBody to body, it works!
body: formData,
headers: {
"Content-Type": "application/json"
},
method: "POST"
}).then(function(response) {
return response.text();
}).then(function(data){
console.log('data', data);
}).catch(function(err){
console.err(err);
});
I already tried with URLSearchParams, but still couldn't make it work.
Thanks.
You shouldn't set the Content-Type header to application/json if you're not sending json. According to this answer, you don't need to set the Content-Type header.
body data type must match "Content-Type" header
Using Fetch
You should either send json data if you set Content-Type to application/json or not set any Content-Type if using FormData API since the fetch function is able to determine the correct Content-Type.
See here for more informations.
I'm sending post-request from front using axios
var data = {
key1: value1,
};
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios({
method: 'post',
url: 'my_url',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8'
},
data: JSON.stringify(data),
}).then(function (response) {
console.log(response);
});
But on django-backend I got bytes object b'{"key1":"value1"}'
Is there a way to get a json object on the backend? Or do I need to decode the request?
You don't need to use JSON.stringify with Axios. Axios handles it internally. Just send the plain javascript object to the backend like this
axios({
method: 'post',
url: 'my_url',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8'
},
data: data,
})
If you do use stringify, Axios takes that string as JSON and stringifies it again internally, that why you Django is not able to decode it.
EDIT
As per your comment on the question, I can see you are using a simple Django view to handle the request. Django views use WSGIRequest object as their request parameter. Because JSON is sent as the request body, they do nothing to it (do not parse) and present original data as it is. that's why you are seeing bytes object as request.body. You can manually parse it using json module from python standard library like this.
request.data = json.loads(request.body)
Or if you want more API compatible request object, I recommend using api_view decorator from Django rest framework like this
#api_view(http_allowed_methods=['post'])
def func(request):
pass
It will wrap your request with Request object from rest_framework.request module which will handle all parsing for you and present parsed data as request.data. You can read more about it here.
I want to post pdf files to spring, using formData.
Javascript Code:
var formData=new FormData();
formData.append("file",file);
$http({
method: 'POST',
accept: 'multipart/form-data',
url: '/upload',
contentType: 'multipart/form-data',
data: formData
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});
Spring Code:
#Controller
public class upload {
#RequestMapping(value = "/upload", method = RequestMethod.POST,consumes="multipart/form-data", headers = "content-type=multipart/form-data")
private void upload(MultipartHttpServletRequest request, HttpServletResponse response){
}
}
I get the Error "415 (Unsupported Media Type)" when using this code. I tried to post json objects (application/json instead of multipart/form-data) and it worked perfectly.
Is multipart/form-data the wrong type to use in my case? Or is there just an error in the code?
I would be very thankful for potential help.
The Accept part is wrong, you don't need that.
$http don't handle that much files natively, use https://github.com/danialfarid/ng-file-upload in order to be able to handle files, add validation on your form about the files (size, type, ...).
For a raw $http solution check the 2nd most upvated answer here : Angularjs $http post file and form data
For some reason, I can't get file transfers to work via fetch. My code is really simple:
export function updateProfilePicture(apiKey, userID, picture) {
let data = new FormData();
data.append('picture', picture);
return fetch(`${API_URL}/v1/${ROOT}/update_profile_picture/${userID}`,{
headers: {'Authorization': `Token token=${apiKey}`},
method: 'POST',
data: data
}).then(response => response.json());
}
However, the resulting request does not seem to include any file whatsoever. Am I missing something? In the above example, picture is instance an of File
There could be two reasons:
data field in Fetch API is called body. Use this instead of data property.
(optional) You need to add another header: 'Content-Type', 'multipart/form-data'
Read more about Fetch API:
https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en
https://developer.mozilla.org/en/docs/Web/API/Fetch_API
Fetch polyfill
I am trying to upload an image inside an Angular app, the code looks like this:
var f = document.getElementById('product-image').files[0],
r = new FileReader();
r.onloadend = function (e) {
var data = e.target.result;
$http({
method: 'POST',
data: data,
url: host + '/uploadFile?' + $rootScope.user._id,
headers: {
'Content-Type': 'multipart/form-data',
'X-File-Name': f.name,
'X-File-Size': f.size,
'X-File-Type': f.type
}
})
.success(function (data, status, headers, config) {
console.log(data)
});
}
r.readAsArrayBuffer(f);
When I have a look at Chrome Header fields of the request, they all look good with values.
Now, how do I access and save that file from the backend endpoint in NodeJS and Express? Do I look inside req variable as usual? Where do I look for the file and its content and meta?
basically, your post request is not 'multipart/form-data', and the data you sent to server is just binary array.
So you could just using NodeJS to save the trunk of binary data to some place.
You need to handle the data different way from normal form upload with files.
If you really want the server to handle the file upload as normal way, you could check the https://github.com/danialfarid/angular-file-upload