i am trying to upload image in angular.
I do this step:
In service i use this settings:
postFormDataToServerMultiPart(action: string, formData) {
var headerss = new HttpHeaders({
"Content-Type": "multipart/form-data"
});
return this.http
.post(HttpService.apiUrl + action, formData, { headers: headerss })
.pipe(map((response: any) => response));
}
headers contain : "Content-Type": "multipart/form-data"
In component.ts :
var formData = new FormData();
formData.append("file", this.imageForm.get("profile").value);
if (this.Image) {
this.httpService
.postFormDataToServerMultiPart(
"api/upload/driver_image?id=" + this.employeeId,
formData
)
.subscribe((resp) => {
console.log("edit", resp);
if (resp.status == "SUCCESS") {
var dialogRef = this.dialog.open(DisplayPopupComponent, {
data: {
title: "Driver Updated Successfully!",
},
............
I receive this error :
error: "Internal Server Error"
message: "Current request is not a multipart request"
path: "/api/upload/driver_image"
status: 500
timestamp: "2021-07-09T13:45:23.443+0000"
what i do wrong?
What in miss?
This is failing because you are manually setting the Content-Type header instead of letting the browser do this for you. If you send that request with your code as-is, go into the dev tools and check out the request headers. You'll see:
Content-Type: multipart/form-data
This is actually not complete, as you are missing the boundary. Simply removing the manual headers should fix this because the browser will properly set the Content-Type and add the boundaries.
postFormDataToServerMultiPart(action: string, formData) {
return this.http
.post(HttpService.apiUrl + action, formData)
.pipe(map((response: any) => response));
}
After sending this request, check the dev tools again for the request headers and you'll see something like:
Content-Type: multipart/form-data; boundary=----12345678901234567890
For more information see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#directives
Related
I am using html2canvas to convert HTML to images.
So whenever the user submits the form, I am trying to send the image as blob and other details to the API using formData.
I am sending formData to the API to process the submitted data.
When user click on submit button, below code is responsible.
function handleReport(target = 'body') {
html2canvas(document.querySelector(target))
.then((canvas) => {
let pngUrl = canvas.toDataURL(); // PNG is the default
fetch(pngUrl)
.then((res) => res.blob())
.then((blob) => {
const formData = new FormData();
formData.append('images', [blob]);
// textarea content
formData.append('description', textAreaValue);
// user device info
formData.append('device[platform]', device.payload.platform);
formData.append('device[name]', device.payload.name);
formData.append('device[version]', device.payload.version);
formData.append('device[ip]', device.payload.ip);
formData.append('device[id]', device.payload.id);
formData.append('device[app_version]', device.payload.app_version);
formData.append('device[device_token]', device.payload.device_token);
dispatch(actions.contactUs(util.getApiToken(), util.getToken(), formData));
});
})
.catch((error) => {
console.log(error);
});
}
action definition :
export function contactUs(apitoken, token, payload) {
return {
[RSAA]: {
endpoint: `${API_ENDPOINT}/contact-us?api_token=${apitoken}`,
headers: {
...AUTH_HEADERS,
Authorization: `Bearer ${token}`,
},
method: 'POST',
body: payload,
// body: JSON.stringify(payload),
types: [
types.CONTACT_US_REQUEST,
types.CONTACT_US_RECEIVE,
],
},
};
}
Given below is the screenshot (not full screenshot) of payload (what user sent after clicking submit button) in Chrome browser
and this is the response I am getting from API
What is my problem !
I am sending all required keys (refer formData) but don't why am I getting error like :
description field is required
My header content is -
AUTH_HEADERS = {
'X-Authorization': X_AUTHORIZATION,
'Content-Type': 'application/json',
};
I just resolved my issue by removing 'Content-Type': 'application/json' which I was sending.
Now I am sending request to API without header.
headers: {
'X-Authorization': X_AUTHORIZATION,
Authorization: `Bearer ${token}`,
},
Now everything is working is fine.
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.
I'm calling a simple login API with POST request following are the params:
Headers:
Content-type: application/x-www-form-urlencoded
Body:
email: String
password
Error returned from server is:422 Unprocessable Entity
CODE:
var formBody = new FormData();
formBody.set("email", "test5#gmail.com");
formBody.set("password", "12345678");
const data = new URLSearchParams(new FormData(details));
return dispatch => {
dispatch(requestData());
try {
fetch(`${BASE_URL}users/sign_in`, {
method: 'POST',
// headers: Interceptor.getHeaders(),
headers: {
Accept:'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
// body: formBody
body: data
})
.then(res => res.json())
.then(result=>
{
if (result.success === false) {}
}
)
} catch (error) {
console.log('error',error)
dispatch(failureData(error))
}
}
Screenshot of code
Got the answer, 422 is basically caused by semantic issue, in my case, Origin of my Request Header was going null.
I'm encountering a bit of a roadblock in my dev work. I'm trying to upload a photo that I'm sending using FormData in fetch. I'm guessing my problem is in my content header or my back-end handling. Eitherway, I can't seem to find a way around it. I hope you guys can help me
general.js - this is my handler for a request
export const postDataWithImage = (url, data) => {
return fetch(url, {
body: data, // must match 'Content-Type' header
credentials: 'same-origin', //pass cookies, for authentication
method: 'POST',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
})
.then(response => response.json()); // parses response to JSON
};
user-creation.js - my actual usage of the function above (sending multiple data)
heres an image of the data I'm sending
![1] https://imgur.com/leBlC7L
const data = {...this.state, ...form};
const formData = new FormData();
Object.entries(data).forEach(([key, value]) => formData.append(key, value));
postDataWithImage('/users', data)
.then(data => {
if (data.error) {
console.log("theres an error");
this.setState({
error: data["error"]
});
console.log(this.state.error);
} else {
console.log(data["data"]);
}
})
.catch(error => message.warning(error.message));
views.py - my backend handler using Django REST not: this returns me an error either byte has no attribute 'get'... or an empty ModelDict for request.FILES
#staticmethod
def post(request):
print(request.body.get('image'))
print(request.FILES)
if "username" not in request.data or "password" not in request.data:
return Response(data={
"error": "Missing username or password"
}, status=400, content_type="application/json")
return Response(data=data, status=200, content_type="application/json")
Please help me I'm really stuck. Thank you!
I faced similar problem using Vue.js and Django.
Finally I noticed that the problem was that: boundary was not set to the header.
The solution is to remove headers from your request like this:
fetch(url, {
body: data, // assume this is some binary data
method: 'POST',
})
Then, your browser will automatically add proper headers for your request. And you will see boundary field which is added by your browser in your request headers.
Try to remove the "Content-Type" from the headers of fetch
I want to send data to my sever but I got this error:
TypeError: Failed to fetch
my codes:
function login(username, password) {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json','charset':'utf-8' },
body: JSON.stringify({ 'username':username , 'password':password })
};
console.log(requestOptions);
return fetch(BASE_URL+serverConstants.LOGIN_POST_REQUEST, requestOptions)
.then(response => {
if (!response.ok) {
return Promise.reject(response.statusText);
}
return response.json();
})
.then(user => {
// login successful if there's a jwt token in the response
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify(user));
}
return user;
});
}
but I tested it on postman I got correct response.
Your preflight request is failing. Allow cross origin for the API you are hitting:
In node you do it like this,
res.header("Access-Control-Allow-Origin", "*");
Hope this helps
If you want to send values to your sever like form-data from postman sowftware you should use formData (your don't need to import FormData from any class):
var formData = new FormData()
formData.append('yourKey, 'yourValue');
var requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json'
},
body: formData
};
return fetch('Your url', options)
.then(checkStatus)
.then(parseJSON);
of course from your server-side you should enable CORS. CORS depending on your language server-side is different.