How to send FormData (POST) via xhr or fetch()? - javascript

I want to translate the jQuery code into plain javascript.
I have this function above.
$.post(
"/product/getList",
{
id: id,
product_id: product_id.value,
}
).done(function(data) {
console.log(data)
});
this will send data as FormData code=test&product=227
I tried with xhr
let xhr = new XMLHttpRequest();
xhr.open("POST", "/product/getList", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
id: id,
product_id: product_id.value,
}));
xhr.onload = function() {
let data = JSON.parse(this.responseText);
console.log(data)
}
and fetch
fetch("/product/getList", {
method: "POST",
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: id,
product_id: product_id.value,
})
}).then(response => {
console.log(response)
});
but both functions send data as Request Body {"code":"s","product":"227"}
How i can send also FormData via xhr and fetch() ?
---------------------- Updated: ----------------------
This is the FormData when i use $.post()
This is my FormData using
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
const formData = new FormData();
formData.append("id", id);
formData.append("product_id", product_id);
and try header
headers: {
"Content-Type": "application/json",
},

You can create the FormData object and fill it with your props.
const formData = new FormData();
formData.append('id', id);
formData.append('product_id', product_id.value);
// and send it
xhr.send(formData);
// OR
fetch("/product/getList", {
method: "POST",
body: formData
})
But remember that formData.append(..) adds one more field even if it already exists in formData so you can use formData.set(..) instead to ensure your formData has unique fields only.
You can find some docs on developer.mozilla.org

Related

Trying to post data using axios and formData but it's empty

I'm using Vue3 and axios to post a form using FormData, but it's empty, nothing is being passed.
{"formData":{}}
Here's what I am doing:
const formData= new FormData();
formData.set("name", name);
axios.post("postform", formData);
I also tried this:
formData.set("name", "John Doe");
axios.post("postform", formData);
and this:
formData.append("name", "John Doe");
axios.post("postform", formData);
But no success. There's no errors, it's just empty.
I retrieve them in PHP like this:
echo $request->input("name");
So my question is:
How do I post data using FormData?
If you are not sending any file (or your form is not maltipart/form-data) you can use following method to send data through axios:
let formData = {};
formData.name = "John Doe";
axios({
url: "postform",
method: "POST",
data: formData
});
EDIT:
If you are sending any files then in my case following worked for me:
const formData = new FormData();
formData.append("name", "hello world");
axios({
url: 'postform',
method: "POST",
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
You can convert your FormData Object to simple object and then send that object to server.
const formData = new FormData();
formData.set("key1", "value1");
formData.set("key2", "value2");
let data = {};
// convert the key/value pairs
for(var pair of formData.entries()) {
data[pair[0]] = pair[1];
}
axios.post("postform", data);
You might need to send the header 'Content-Length': formData.getLengthSync(). This call works for me:
const response = await axios.delete(url, {
"data": formData,
"headers": {
"Content-Length": formData.getLengthSync()
}
});

React ajax request with multipart file and json data

I have a base request like this:
export const request = (options) => {
const headers = new Headers({
'Content-Type': 'application/json',
});
if (Common.getToken()) {
headers.append('Authorization', 'Bearer ' + Common.getToken())
}
const defaults = {headers: headers};
options = Object.assign({}, defaults, options);
return fetch(options.url, options)
.then(response =>
response.json().then(json => {
if (!response.ok) {
return Promise.reject(json);
}
return json;
})
);
};
and my ajax request:
onCreateNewPost(postDataRequest, photoBody) {
const formData = new FormData();
formData.append('photo', photoBody);
formData.append('postData', JSON.stringify(postDataRequest));
return request({
url: API_BASE_URL + '/posts/new-post',
method: 'POST',
body: formData
});
};
where postDataRequest - json object included post title, description etc...
photoBody - image file.
In the backend I have a controller's method:
#PostMapping(value = "/api/posts/new-post")
#PreAuthorize("hasRole('ADMIN')")
public ResponseEntity createNewPost(#CurrentUser UserPrincipal currentUser,
#RequestBody NewPostDataRequest postRequest,
#RequestParam MultipartFile photo) {
// method body
return ResponseEntity.ok(new ActionCompleteResponse(true));
}
but when I send a request, I get Status Code: 400. What is the problem? I can separately send either json data or multipart data, but I can’t figure out how to transfer them together with one request. I tried to put headers without a Content-Type in the request, as in the code below, so that the request itself indicates it, but in response I get code 415.
onCreateNewPost(postDataRequest, photoBody) {
const formData = new FormData();
formData.append('photo', photoBody);
formData.append('postData', JSON.stringify(postDataRequest));
const headers = new Headers({});
if (Common.getToken()) {
headers.append('Authorization', 'Bearer ' + Common.getToken());
}
return request({
url: API_BASE_URL + '/posts/new-post',
headers: headers,
method: 'POST',
body: formData
});
};
What should I do?
Okay, I found the solution:
1. Clear headers data (except Authorization token)
2. Add to #PostMapping consumes = MediaType.MULTIPART_FORM_DATA_VALUE and add #RequestPart to method parameter
ajax request like:
onCreateNewPost(postDataRequest, photoBody) {
const formData = new FormData();
formData.append('post', new Blob([JSON.stringify(postDataRequest)], {
type: "application/json"
}));
formData.append('photo', photoBody);
const headers = new Headers({});
if (Common.getToken()) {
headers.append('Authorization', 'Bearer ' + Common.getToken())
}
return request({
url: API_BASE_URL + '/posts/new-post',
method: 'POST',
headers: headers,
body: formData
});
};
and spring controller like
#PostMapping(value = "/new-post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#PreAuthorize("hasRole('USER')")
public ResponseEntity createNewPost(#CurrentUser UserPrincipal currentUser,
#RequestPart("post") #Valid PostEntity post,
#RequestPart("photo") #Valid MultipartFile photo) throws IOException {
post.setAuthor(currentUser.getUsername());
post.setAuthorId(currentUser.getId());
post.setCommentsCount(0L);
post.setDate(LocalDate.now());
post.setPhoto(photo.getBytes());
postService.save(post);
return ResponseEntity.ok(new ActionCompleteResponse(true));
}
#Sergey Scream solution is correct, I just want to add some information to clarify the problem.
So if you want to send json and a file using FormData you have to wrap your json in a blob including the type like he did:
formData.append('post', new Blob([JSON.stringify(postDataRequest)], {
type: "application/json"
}));
Adding your json like this will not work:
formData.append('post', JSON.stringify(postDataRequest));
You're setting Content-Type to application/json in request but body to form data in onCreateNewPost. If you removed line 3 from request then your current solution should work.
Also you're setting the Authorization header twice in onCreateNewPost and request.

sending file and json in POST multipart/form-data request with axios

I am trying to send a file and some json in the same multipart POST request to my REST endpoint. The request is made directly from javascript using axios library as shown in the method below.
doAjaxPost() {
var formData = new FormData();
var file = document.querySelector('#file');
formData.append("file", file.files[0]);
formData.append("document", documentJson);
axios({
method: 'post',
url: 'http://192.168.1.69:8080/api/files',
data: formData,
})
.then(function (response) {
console.log(response);
})
.catch(function (response) {
console.log(response);
});
}
However, the problem is when I inspect the request in chrome developer tools in the network tab, I find no Content-Type field for document, while for file field Content-Type is application/pdf (I'm sending a pdf file).
On the server Content-Type for document is text/plain;charset=us-ascii.
Update:
I managed to make a correct request via Postman, by sending document as a .json file. Though I discovered this only works on Linux/Mac.
To set a content-type you need to pass a file-like object. You can create one using a Blob.
const obj = {
hello: "world"
};
const json = JSON.stringify(obj);
const blob = new Blob([json], {
type: 'application/json'
});
const data = new FormData();
data.append("document", blob);
axios({
method: 'post',
url: '/sample',
data: data,
})
Try this.
doAjaxPost() {
var formData = new FormData();
var file = document.querySelector('#file');
formData.append("file", file.files[0]);
// formData.append("document", documentJson); instead of this, use the line below.
formData.append("document", JSON.stringify(documentJson));
axios({
method: 'post',
url: 'http://192.168.1.69:8080/api/files',
data: formData,
})
.then(function (response) {
console.log(response);
})
.catch(function (response) {
console.log(response);
});
}
You can decode this stringified JSON in the back-end.
you only need to add the right headers to your request
axios({
method: 'post',
url: 'http://192.168.1.69:8080/api/files',
data: formData,
header: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
})
You cant set content-type to documentJson, because non-file fields must not have a Content-Type header, see HTML 5 spec 4.10.21.8 multipart form data.
And there`s two way to achieve your goals:
JSON.stringify your data, and decode it in the back-end like this answer below
pass a file-like object and set Content-Type like this answer below

How do I upload a file from Axios to Django?

I'm switching from Jquery AJAX to react-dropzone & Axios, I'd like to upload a file to my Django server, I have no issue posting a blob url of the image on the server but I want to get it under request.FILES but I am getting an empty queryset.
request.FILES : <MultiValueDict: {}> <!--- empty
request.POST : <QueryDict: {}> <!--- able to get a blob url
Here's what my axios configuration looks like :
const temporaryURL = URL.createObjectURL(step3.drop[0]);
var fd = new FormData();
fd.append('image', temporaryURL);
axios({
method: 'post',
url: SITE_DOMAIN_NAME + '/business-card/collect/',
data: fd,
headers: {
"X-CSRFToken": CSRF_TOKEN,
"content-type": "application/x-www-form-urlencoded"
}
}).then(function (response) {
console.log(response)
URL.revokeObjectURL(temporaryURL);
}).catch(function (error) {
console.log(error)
});
I am receiving the file on a classBasedView on POST request.
How can I upload the file? Where am I wrong?
Edit
I also tried "application/form-data", doesn't solve the problem
the problem came from the content-type as it was using "application/form-data" instead of "multipart/form-data".
I am answering in case, someone comes here by searching on google:
let formData = new FormData();
formData.append('myFile', file);
formData.append('otherParam', 'myValue');
axios({
method: 'post',
url: 'myUrl',
data: formData,
headers: {
'content-type': 'multipart/form-data'
}
}).then(function (response) {
// on success
}).catch(function (error) {
// on error
});

Error when POST file multipart/form-data (JavaScript)

I got an error every time when trying to POST data to the API.
Request:
changeUserAvatar(authParam, file) {
let formData = new FormData();
//file is actually new FileReader.readAsDataURL(myId.files[0]);
formData.append('profile_image', file);
fetch(BASE_URL + 'profile-image', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': authParam
},
body: formData
}).then((response) => {
return response.json();
}).then((response) => {
debugger;
}).catch((error) => {
console.error(error);
});
}
Error: profile_image can not be blank (422).
But it's not blank!
Request payload:
What do I do wrong?
Solved at GutHub: https://github.com/github/fetch/issues/505
I just had to leave Header without pointing any Content-Type manually.

Categories