I am getting "MissingServletRequestPartException: Required request part 'studentImg' is not present", It works fine with Postman but not with React. I am trying to call a end point in a Spring boot restful API.
Backend Controller Code:
#PostMapping("/add")
public ResponseEntity<StudentFile> addStudentImg(HttpServletRequest request, #RequestParam("studentImg") MultipartFile studentImg) {
boolean isStudent = (Boolean) request.getAttribute("isStudent");
if(false == isStudent) {
throw new EtAuthException("Only Student can add their image.");
} else {
Long addedBy = (Long) request.getAttribute("studentId");
StudentFile studentFile = studentFileService.addStudentImg(studentImg, addedBy);
return new ResponseEntity<>(studentFile, HttpStatus.CREATED);
}
}
React Components' Code Snippets:
handleStudentImgChange(event) {
this.setState({ studentImg: event.target.files[0] });
}
handleOnSubmit(event) {
event.preventDefault();
const { studentImg } = this.state;
this.props.addStudentImg(studentImg);
this.setState({ studentImg: null });
}
const mapDispatchToProps = (dispatch) => {
return {
addStudentImg: (studentImg) => {
dispatch(addStudentImgAction(studentImg));
},
};
export default connect(null, mapDispatchToProps)(AddStudentImgPage);
React Axios Call:
import axios from "axios";
const token = "...";
export const addStudentImg = (studentImg) => {
let bodyFormData = new FormData();
bodyFormData.append("studentImg", studentImg[0]);
const headers = {
Authorization: `Bearer ${token}`,
// Accept: "application/json",
"Content-Type": "multipart/form-data",
};
return axios
.request({
method: "POST",
url: "http://localhost:8080/api/studentfiles/add/",
data: bodyFormData,
headers: headers,
})
.then((res) => res.data);
};
The network log: enter image description here enter image description here
I'm unable to find any solution regarding that. Please give suggestions.
Thanks in Advance :D
You already set files[0] when you set
handleStudentImgChange(event) {
this.setState({ studentImg: event.target.files[0] });
}
then again, you are trying to access
bodyFormData.append("studentImg", studentImg[0]);
This, seems wrong, change this to
bodyFormData.append("studentImg", studentImg);
and see if it works..
First I changed these lines:
let bodyFormData = new FormData();
bodyFormData.append("studentImg", studentImg[0]);
With these:
const bodyFormData = new FormData();
const blob = new Blob([studentImg], {type: studentImg.type});
bodyFormData.append("studentImg", blob);
When I logged studentImg just above the bodyFormData, I get the response something like: {type: 'ADD_STUDENT_IMG', studentImg: File} where it was json object like this:
Then, I put thse lines and these are just working fine with it.
const bodyFormData = new FormData();
const blob = new Blob([studentImg.studentImg], {
type: studentImg.studentImg.type,
});
bodyFormData.append("studentImg", blob);
To understand how these lines are working:
Please read the FormData docs and also some additional information about how it's serialized over here.
If any queries, please ask. (P.S. prescriptionImg == studentImg for fig.)
Thanks :D
Related
I have a NestJs project in my controller I accept an Express.Multer.File but I need to send it to another server. How can I convert it to Blob for passing to FormData?
#action in my controller
#Post('/upload')
#UseInterceptors(FileInterceptor('avatar'))
async uploadUserProfileAvatar(#UploadedFile() file: Express.Multer.File){
console.log(file)
let blob = new Blob(file.mimetype)
let formData = new FormData()
//can't set because file is not Blob
formData.append('file',file)
let request$ = this.httpService.post('http://test_server/file',formData,{headers:{
'Content-Type':'multipart/form-data'
}}).pipe(
map(response => response.data)
)
request$.subscribe( response => {
console.log(response)
return response
})
}
I will be grateful for every answer!
EDIT:
Thanks again for your help! As a result, I managed to successfully send the code in this way:
#Post('/upload')
#UseInterceptors(FileInterceptor('avatar'))
async uploadUserProfileAvatar(#UploadedFile() file: Express.Multer.File){
const FormData = require('form-data');
const formData = new FormData();
formData.append('file', Buffer.from(file.buffer) , file.originalname);
let request$ = this.httpService.post('http://nginx_files/file',formData,{headers:formData.getHeaders()}).pipe(
map(response => response.data)
)
request$.subscribe( response => {
console.log(response)
return response
})
}
Use formdata package like this:
const FormData = require('form-data');
const formData = new FormData();
formData.append('file', fileContent, 'file_name.ext');
let request$ = this.httpService.post('http://test_server/file',
formData,
{ headers: formData.getHeaders() }
).pipe(
map(response => response.data)
)
#MiyRon
You get the Error "TypeError: source.on is not a function", because formData accepts only three types of elements. String, Buffer and Stream.
So you can fix it with:
formData.append('file', JSON.stringify(fileContent), 'file_name.ext');
Encountered same issue, but initial answer didn't work for me, had to add Content-Length header and contentType, so code looks something like this:
import * as FormData from 'form-data';
// ...
processFile(file: Express.Multer.File) {
const formData = new FormData();
formData.append('file', Buffer.from(file.buffer), {
filename: file.originalname,
contentType: file.mimetype,
});
return this.httpService
.post('http://test_server/file', formData, {
headers: {
...formData.getHeaders(),
'Content-Length': `${formData.getLengthSync()}`,
},
})
.pipe(map((response) => response.data));
}
Based on this comment
Using raw HTML when I post a file to a flask server using the following I can access files from the flask request global:
<form id="uploadForm" action='upload_file' role="form" method="post" enctype=multipart/form-data>
<input type="file" id="file" name="file">
<input type=submit value=Upload>
</form>
In flask:
def post(self):
if 'file' in request.files:
....
When I try to do the same with Axios the flask request global is empty:
<form id="uploadForm" enctype="multipart/form-data" v-on:change="uploadFile">
<input type="file" id="file" name="file">
</form>
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
If I use the same uploadFile function above but remove the headers json from the axios.post method I get in the form key of my flask request object a csv list of string values (file is a .csv).
How can I get a file object sent via axios?
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Sample application using Vue. Requires a backend server running on localhost to process the request:
var app = new Vue({
el: "#app",
data: {
file: ''
},
methods: {
submitFile() {
let formData = new FormData();
formData.append('file', this.file);
console.log('>> formData >> ', formData);
// You should have a server side REST API
axios.post('http://localhost:8080/restapi/fileupload',
formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
},
handleFileUpload() {
this.file = this.$refs.file.files[0];
console.log('>>>> 1st element in files array >>>> ', this.file);
}
}
});
https://codepen.io/pmarimuthu/pen/MqqaOE
If you don't want to use a FormData object (e.g. your API takes specific content-type signatures and multipart/formdata isn't one of them) then you can do this instead:
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': file.type
}
})
}
Sharing my experience with React & HTML input
Define input field
<input type="file" onChange={onChange} accept ="image/*"/>
Define onChange listener
const onChange = (e) => {
let url = "https://<server-url>/api/upload";
let file = e.target.files[0];
uploadFile(url, file);
};
const uploadFile = (url, file) => {
let formData = new FormData();
formData.append("file", file);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
fnSuccess(response);
}).catch((error) => {
fnFail(error);
});
};
const fnSuccess = (response) => {
//Add success handling
};
const fnFail = (error) => {
//Add failed handling
};
This works for me, I hope helps to someone.
var frm = $('#frm');
let formData = new FormData(frm[0]);
axios.post('your-url', formData)
.then(res => {
console.log({res});
}).catch(err => {
console.error({err});
});
this is my way:
var formData = new FormData(formElement);
// formData.append("image", imgFile.files[0]);
const res = await axios.post(
"link-handle",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
How to post file using an object in memory (like a JSON object):
import axios from 'axios';
import * as FormData from 'form-data'
async function sendData(jsonData){
// const payload = JSON.stringify({ hello: 'world'});
const payload = JSON.stringify(jsonData);
const bufferObject = Buffer.from(payload, 'utf-8');
const file = new FormData();
file.append('upload_file', bufferObject, "b.json");
const response = await axios.post(
lovelyURL,
file,
headers: file.getHeaders()
).toPromise();
console.log(response?.data);
}
There is an issue with Axios version 0.25.0 > to 0.27.2 where FormData object in a PUT request is not handled correctly if you have appended more than one field but is fine with one field containing a file, POST works fine.
Also Axios 0.25.0+ automatically sets the correct headers so there is no need to specify Content-Type.
For me the error was the actual parameter name in my controller... Took me a while to figure out, perhaps it will help someone. Im using Next.js / .Net 6
Client:
export const test = async (event: any) => {
const token = useAuthStore.getState().token;
console.log(event + 'the event')
if (token) {
const formData = new FormData();
formData.append("img", event);
const res = await axios.post(baseUrl + '/products/uploadproductimage', formData, {
headers: {
'Authorization': `bearer ${token}`
}
})
return res
}
return null
}
Server:
[HttpPost("uploadproductimage")]
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
{
return Ok();
}
Error here because server is expecting param "image" and not "img:
formData.append("img", event);
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
Okay so i have some code where an user can upload Images. He can upload a multiple images. The thing is that when the user uploads the pictures and there is a request sent to the server I get a 500 error code.
The code:
ChangeImages(images) {
this.images = images;
console.log("imagesEmit", this.images);
console.log(this.step);
console.log("images", images);
console.log("thishome", this.home);
const formData = new FormData();
let id = this.homeId;
formData.append(
"data",
JSON.stringify({ file: this.images[0], position: 1 })
);
console.log(formData);
axios
.post(`/api/upload-home-picture/${id}`, formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
this.home.images[0].push(response.data);
});
},
So here as you see I am sending the request in a listener. I am gonna show the results in console.logs:
this.images:
```"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABsoA…wD3k6myVTczaWMZ5Ebv8P2lNvc037YOAAAAAASUVORK5CYII="`````
this.home:
funding_round_end: (...)
funding_round_start: (...)
funding_round_time: (...)
hpi_zip_avg_appreciation: (...)
id: (...)
images: (...)
info: (...)
interest: (...)
invest_now: (...)
Also the payload:
{"images":"data:image/png;base64,
And the backend code:
#bp.route('/upload-home-picture', methods=['POST'])
#login_required
def upload_home_picture():
# TODO test permission
data = json.loads(request.form['data'])
home_id = data['home']
home = UserHome.query.get(home_id)
url = _upload_file()
db.session.add(UserHomeImage(url=url, home=home, pos=0))
db.session.commit()
result = dict(url=url, pos=0)
return jsonify(result)
´´´
It is better to send an image without JSON.stringify.
onUpload() {
let formData = new FormData();
formData.append('file', this.images[0]);
axios.post(
`/api/upload-home-picture/${id}`
,formData
,{headers: {"Content-Type": "multipart/form-data"}}
)
.then((response) => {
this.home.images[0].push(response.data);
});
.catch(e => {
//...
})
}
And it will be easier to get it as a file in Python.
i am new at react native. I fetch data on Firebase but i want to fetch it JSON file. My JSON file like this: enter image description here
how can i change firebase url to my php json url?
PLEASE HELP ME
This is my code:
return async (dispatch, getState) => {
// any async code you want!
// const userId = getState().auth.userId;
try {
const response = await fetch(
'https://shopapp-f9964.firebaseio.com/products.json'
);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const resData = await response.json();
const loadedProducts = [];
for (const key in resData) {
console.log(resData[key].description);
loadedProducts.push(
new Product(
0,
0,
resData[key].product_image,
resData[key].description,
resData[key].price,
)
);
}
dispatch({
type: SET_PRODUCTS,
products: loadedProducts,
//userProducts: loadedProducts.filter(prod => prod.ownerId === userId)
});
} catch (err) {
// send to custom analytics server
throw err;
}
};
Here is the way to get from API (or Json response).
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
Here is the official docs, it really helps for you to understand data from JSON file
https://reactnative.dev/docs/network
here is the working example on Snack
https://snack.expo.io/#asad_4561/b21f6d?session_id=snack-session-EGg1r5WPo&preview=true&platform=web&iframeId=g11cgnoglm&supportedPlatforms=ios,android,web&name=Fetch%20Example&description=Example%20usage&waitForData=true
Here is some good refs for your problem, by reading them your problems will be solved:
Medium: This is very good
RN docs
Another Good ref
I have the following data being added to my formData()
let uploadData = new FormData();
uploadData.append("peer-video", this.state.peerVideo);
uploadData.append("peer-video-thumbnail", this.state.peerVideoThumbnail);
uploadData.append("project-video", this.state.projectVideo);
uploadData.append(
"project-video-thumbnail",
this.state.projectVideoThumbnail
);
this.state.documents.forEach(item => {
uploadData.append("documents", item);
});
The uploadData has key value pairs in it, I did formData.entries() to check this. And my axios request is as follows:
export const addProject = data => dispatch => {
axios
.post("/api/portfolio/add-project", data, {
headers: {
"Content-Type": `multipart/form-data`
}
})
.then(res => {
dispatch({
type: ADD_PROJECT,
payload: res.data
});
})
.catch(err => {
dispatch({
type: ADD_PROJECT,
payload: err
});
});
};
And if I go to my payload in the network tab I see this:
{"uploadData":{}}
Any suggestions? Thank you for taking the time to help me.
Edit
I tried the following structure in my axios request and it yielded the same result.
axios({
method: "post",
url: "/api/portfolio/add-project",
data: data,
config: { headers: { "Content-Type": "multipart/form-data" } }
})
When I execute the following
for (let keys of uploadData.entries()) {
console.log(keys);
}
These are the values:
I also noticed on formData docs that
Note: If you specify a Blob as the data to append to the FormData object, the filename that will be reported to the server in the "Content-Disposition" header used to vary from browser to browser.
But i'm not sure if that's what is causing my issue here?
Welp, this is what happens when your eyes stare at a screen too long.
this.props.addProject({
title: this.state.title,
company: this.state.company,
description: this.state.description,
role: this.state.role,
skills: this.state.skills,
uploadData: uploadData
});
Needed to simply be:
this.props.addProject(uploadData)
Thank you #vortex
Looks like you are posting an undefined variable called data rather than your uploadData