How to send multipart request in angular 6? - spring-boot

I need to send a multipart request.
When I am submitting the form I am getting below error from backend,
Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
I am able to hit from Advanced rest client, but facing issue with angular.
On backend side below is The REST endpoint.
#PostMapping("/createCIF")
public Response < Map < String, Object >> createCIF(
#RequestPart("actDocs") List < MultipartFile > actDocs,
#Valid #RequestPart("createCIFReq") CreateCIFReq createCIFReq,
HttpServletRequest request) throws URISyntaxException {
}
Below is the angular side code in component.ts file.
let formData = new FormData();
formData.append('actDocs', this.userInfoService.mulitPartFileArray);
formData.append('createCIFReq', JSON.stringify(this.userInfo));
this.userInfoService.createCif(formData)
.pipe(first())
.subscribe(
data => {
}
}
Angular side Service level code
createCif(formData): any {
return this.http.post<any>(this.url + 'createCIF',
formData)
.pipe(map(cif => {
return cif;
}));
}

I got stuck on this issue an entire day.
Angular seems to fail to set a correct content-type to the JSON part.
I managed to solve this by creating a Blob :
let formData = new FormData();
formData.append('actDocs', this.userInfoService.mulitPartFileArray);
formData.append(
'createCIFReq',
new Blob([JSON.stringify(this.userInfo)], {type: 'application/json'})
);
Hope it helps.

Related

cant get api from local web server

i want to get data from my api web server. I tested on Postman the data is there, even when I try it on my browser the data is still there. but when i want to use the api in my flutter app why is the api empty.
postman tested
my code to get api.
class DioClient {
final Dio _dio = Dio(
BaseOptions(
baseUrl: 'https://spotify.test/api',
contentType: "application/json",
responseType: ResponseType.json,
)
);
Future<HeaderList> getDatas() async {
Response datas = await _dio.get('/load/songs');
print('data = ${datas.data}');
return HeaderList.fromJson(datas.data);
}
}
my model
class HeaderList {
final int total;
final List<Artist> artist;
final List<Song> songs;
HeaderList({
required this.total,
required this.songs,
required this.artist,
});
factory HeaderList.fromJson(Map<String, dynamic> json) => HeaderList(
total: json['total data'],
artist: List<Artist>.from(json['artist'].map((element) => Artist.fromJson(element))),
songs: List<Song>.from(json['songs'].map((element) => Song.fromJson(element))),
);
}
is there any error in my code or my laravel web project ?. because I'm still a beginner in laravel ?
You shouldn't need Dio for a simple request like this; just use package:http.
There are a couple of problems with your code. In Postman you are using the POST verb, but GET in Dart. You are also telling the server you are sending JSON, but it want (see your Postman request) form data.
Try this:
import 'package:http/http.dart' as http;
void main() async {
final r = await http.post(
Uri.https('spotify.test', 'api/load/songs'),
body: {
'password': 'open123456',
'password_confirmation': 'open123456',
},
);
print(r.statusCode);
print(r.body);
}

Post MultipartFile - Request Part not preset Error

I try to send an image from a ionic Front-End application through a post method to Back-End services in Spring boot
I have done this method that makes the post to the backend url with the image inside a FormData object:
uploadImageService(url: string, image: any) {
console.log('post service: upload Image', + url);
// Initiates a FormData object to be sent to the server
const fd: FormData = new FormData();
fd.append('file', image);
const xhr = new XMLHttpRequest;
console.log('form data file: \n' + fd.get('file'));
xhr.open('POST', url);
// Send the FormData
xhr.send(fd);
console.log(xhr.response);
return xhr.responseText;
}
// call this method:
this.webapiService.uploadImageService(this.globalDataService.getUrlMedium() 'riskcontrol/subir-imagen', this.selectedImage);
This is the spring boot method that collects this post:
#RequestMapping(method = RequestMethod.POST, value = "/subir-imagen")
public ResponseEntity handleFileUpload(#RequestParam("file") MultipartFile file) {
LOGGER.log(Level.INFO, "/Post, handleFileUpload", file);
String associatedFileURL = fileManagerService.storageFile(file);
return ResponseEntity.ok(associatedFileURL);
}
When I do the post of the image I get this error:
.w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]
I have launched the petition through Postman and it has worked,
that's why I think the error is in the tyscript code.
The only difference I see between postman and the code, is that in the form-data, let mark the key as type file or type text, and I have chosen type file.
I tried to make the request post in another way:
const httpOptionsImages = {
headers: new HttpHeaders({
'Content-Type': 'multipart/form-data',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE'
})
};
// function
uploadImageService(url: string, image: any): Observable<any> {
console.log('post service: upload Image', + url);
// Initiates a FormData object to be sent to the server
const fd: FormData = new FormData();
fd.append('file', image);
return this.http
.post(url, fd, httpOptionsImages);
}
// call to the function
this.webapiService.uploadImageService(this.globalDataService.getUrlMedium() + 'riskcontrol/subir-imagen', this.selectedImage)
.subscribe( result => {
console.log(result);
});
But in this way I got another error:
FileUploadException: the request was rejected because no multipart boundary was found
What am I doing wrong?
Is there any way to indicate to FormData that the key is of type file as in postman?
Add the image as a Blob follow Ionic tutorial
const imgBlob = new Blob([reader.result], {type: file.type});
formData.append('file', imgBlob, file.name);
In the readFile function the program utilizes the FileReader from the File API to read the file into an ArrayBuffer. The onloadend event is called as soon as the file is successfully read. The app then creates a FormData object, wraps the array buffer in a Blob and adds it to the FormData object with the name 'file'. This is the same name the server expects as request parameter.
Remove your 'Content-Type': 'multipart/form-data'.
Have you tried on using #RequestPart instead of #RequestParam for MultipartFile file.

How to get each http body updates on angular Http request?

I'm using an express api (my back-end) and an angular app (my front-end).
One express js end point (let's call it '/foo') is processing a lot of files,
i send data using res.write() after each treatment so the http response body is update.
I would like to get this update on my angular app.
I was using ajax in a previous version and it worked fine with ajax call :
xhrFields: {
// Getting on progress streaming response
onprogress: function(e)
{
var progressResponse;
var response = e.currentTarget.response;
if(lastResponseLength === false)
{
progressResponse = response;
lastResponseLength = response.length;
}
else
{
progressResponse = response.substring(lastResponseLength);
lastResponseLength = response.length;
}
actualResponse += progressResponse
}
Unfortunatly i found nothing to get partial http body. I tried to use 'reportProgress' Parameter but it's not working.
For some more context my front-end angular code:
service.ts :
setHolidaysDirectory(holidaysKey: string, path: string): Observable<Object>{
const setHolidayDirectoryStreamHttpRequest =
new HttpRequest('POST', 'http://localhost:8089/holidays/pictures/edit', { 'key': holidaysKey,
'path': path
}, {headers: this._httpHeaders, reportProgress: true, responseType: 'text'});
// pipe stream answer
return this._http.request(setHolidayDirectoryStreamHttpRequest);
}
and my component just call the service and subscribe :
this._holidaysService
.setHolidaysDirectory(key, finalHolidaysForm.path)
.subscribe((stream) => {
console.log('new answer');
console.log(stream);
}, error => console.log(error));
But unfortunatly i got empty answer and all the http body is recovered after res.end() (server side)
Can anyone help pls !
Thank a lot !

Spring Boot multipart.support.MissingServletRequestPartException while sending formData via POST request in Angular

I tried everything, and I am constantly getting this error from Spring Boot
Resolved exception caused by Handler execution: org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
This is my Angular code. NOTE: I am using Http (not HttpClient) for my POST request.
updateUserProfilePicViaHttp(userId: number, imageFile: any) {
let headers: Headers = new Headers()
headers.append('Content-Type', 'multipart/form-data;boundary=imageUpload');
let formData: FormData = new FormData()
formData.append('file', imageFile, imageFile.name)
return this.http.post(this.baseUrl + `user/${userId}/profile_pic`, formData, { headers: headers })
}
This is my Spring Boot code
#RequestMapping(value="/{userId}/profile_pic",
method = RequestMethod.POST,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#ResponseBody
public ResponseEntity<User> uploadProfilePic(#PathVariable("userId") Integer id, #RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes){
IUserDao userDao = (IUserDao) getDao();
User user = null;
try {
user = userDao.saveAndUpdateProfilePic(id, file.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
if( user != null)
return new ResponseEntity<>(user, HttpStatus.OK);
else
return new ResponseEntity<>(user, HttpStatus.NOT_FOUND);
}
I think that there is something wrong with my Angular code, because when I send an image via Postman everything works fine!
Postman image:
Thanks!
EDIT: For some reason I tried replacing #RequestParam("file") MultipartFile file with #RequestParam MultipartFile file in my function.
Still getting the same error
It seems that when Spring says
Required request part 'file' is not present
It associates name 'file' with reference name of MultiPartFile file in my Spring boot function, not with #RequestParam('file').
EDIT2: I listened to Ravat and modified my code a little bit.
How I got imageFile?
Explanation:
#ViewChild('fileInput') myFile: ElementRef reference from <input type="file" #fileInput>
This is what is imageFile in my Angular function.
imageFile = this.myFile.nativeElement.files[0]
But still, same error...
After 6 hours of googling and explaining to Duck Overflow what is the problem, I stumbled upon this.
And I just removed my header
headers.append('Content-Type', 'multipart/form-data;boundary=imageUpload');
Final code
updateUserProfilePicViaHttp(userId: number, imageFile: any) {
let formData: FormData = new FormData()
formData.append('file', imageFile, imageFile.name)
return this.http.post(this.baseUrl + `user/${userId}/profile_pic`, formData)
}
The Issue is in following code code
updateUserProfilePicViaHttp(userId: number, image: string) {...}
I don't know about angular, here you are sending string in an image variable
that definitely won't work because it needs to be a file.

Required request part 'file' is not present - Angular2 Post request

I am trying to get my file upload functionality done using Angular2 and SpringBoot. I can certify that my java code for the file uploading working fine since I have tested it successfully using Postman.
However, when it comes to sending the file from Angular2 front end, I am getting the HTTP 400 response saying Required request part 'file' is not present.
This is how I send the POST request from Angular2.
savePhoto(photoToSave: File) {
let formData: FormData = new FormData();
formData.append('file', photoToSave);
// this will be used to add headers to the requests conditionally later using Custom Request Options
this._globals.setRequestFrom("save-photo");
let savedPath = this._http
.post(this._endpointUrl + "save-photo", formData)
.map(
res => {
return res.json();
}
)
.catch(handleError);
return savedPath;
}
Note that I have written a CustomRequestOptions class which extends BaseRequestOptions in order to append Authorization header and Content Type header. Content Type header will be added conditionally.
Following is the code for that.
#Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
constructor(private _globals: Globals) {
super();
this.headers.set('X-Requested-By', 'Angular 2');
this.headers.append('virglk', "vigamage");
}
merge(options?: RequestOptionsArgs): RequestOptions {
var newOptions = super.merge(options);
let hdr = this._globals.getAuthorization();
newOptions.headers.set("Authorization", hdr);
if(this._globals.getRequestFrom() != "save-photo"){
newOptions.headers.set('Content-Type', 'application/json');
}else{
//request coming from save photo
console.log("request coming from save photo");
}
return newOptions;
}
}
This conditional header appending is working fine. The purpose of doing that is if I add 'Content-Type', 'application/json' header to every request, file upload method in Spring controller will not accept it. (Returns http 415)
Everything seems to be fine. But I get Required request part 'file' is not present error response. Why is that? I am adding that param to the form Data.
let formData: FormData = new FormData();
formData.append('file', photoToSave);
This is the Spring Controller method for your reference.
#RequestMapping(method = RequestMethod.POST, value = "/tender/save-new/save-photo", consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadPhoto(#RequestParam("file") MultipartFile file){
if (file.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage("DEBUG: Attached file is empty");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND);
}
String returnPath = null;
try {
// upload stuff
} catch (IOException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
return new ResponseEntity<ErrorResponse> (errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<String>(returnPath, HttpStatus.OK);
}
EDIT - Adding the payload of the request captured by the browser
As you can see, the param "file" is available there.
Try to add
headers: {
'Content-Type': 'multipart/form-data'
},
to your
.post(this._endpointUrl + "save-photo", formData)
Change formData.append('file', photoToSave);
to              formData.append('file', this.photoToSave, this.photoToSave.name); and also add headers specifying the type of data you are passing to API, in your case it will be 'Content-Type': 'multipart/form-data'. Post the output here if it fails even after changing this.
Is there a chance that you're using zuul in a secondary app that is forwarding the request? I saw this with an update where the headers were stripped while forwarding a multi-part upload. I have a gatekeeper app which forwards requests using zuul to the actual service via a looking from eureka. I fixed it by modifying the url like this:
http://myserver.com/service/upload
to
http://myserver.com/zuul/service/upload
Suddenly the 'file' part of the upload header was no longer stripped away and discarded.
The cause, I suspect was a re-try mechanism which cached requests. On failure, it would re-submit the requests, but somehow for file uploads, it wasn't working properly.
To upload a file to the server, send your file inside a FormData and set content type as multipart/form-data.
export const uploadFile = (url, file, onUploadProgress) => {
let formData = new FormData();
formData.append("file", file);
return axios.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data;charset=UTF-8',
// other headers
},
onUploadProgress,
})
};
To handle file object, be careful with consumes attribute and #RequestPart annotation here.
#PostMapping(value = "/your-upload-path", consumes = "multipart/form-data")
public ResponseEntity<Object> uploadFile(#RequestPart("file") #Valid #NotNull #NotBlank MultipartFile file) {
// .. your service call or logic here
}

Resources