I have a problem with my API which I developed in Spring boot and Angular. when I try to record a new performance with an image I always have the same error linked to the Cors cross origin headers.
Here is my controller and the method used to create a Prestation
@RestController
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RequestMapping("/prestations")
public class PrestationController {
private byte[] bytes;
@Autowired
IPrestationService prestationService;
@Autowired
PrestationRepository prestationRepository;
@Autowired
ServletContext context;
@PostMapping
public ResponseEntity<MessageResponse> savePrestaWithImage(@RequestParam("file") MultipartFile file, @RequestParam("prestation")String prestation)
throws JsonParseException, JsonMappingException, Exception {
Prestation presta = new ObjectMapper().readValue(prestation, Prestation.class);
boolean isExist = new File(context.getRealPath("/Images/")).exists();
if(!isExist){
new File(context.getRealPath("/Images/")).mkdir();
System.out.println("dossier créer");
}
String filename = file.getOriginalFilename(); // je recupere le nom de l'image
String newFileName = FilenameUtils.getBaseName(filename)+"."+FilenameUtils.getExtension(filename);
File serverFile = new File(context.getRealPath("/Images/"+File.separator+newFileName));
try {
System.out.println("Image");
FileUtils.writeByteArrayToFile(serverFile, file.getBytes());
}catch (Exception e){
e.printStackTrace();
}
presta.setPhoto(newFileName);
Prestation prestation1 = prestationRepository.save(presta);
if(prestation1 != null){
return new ResponseEntity<MessageResponse>(new MessageResponse(""), HttpStatus.OK);
}else {
return new ResponseEntity<MessageResponse>(new MessageResponse("Prestation not saved"), HttpStatus.BAD_REQUEST);
}
}
Here is my angular service
savePrestation(prestation: Prestation): Observable<Prestation> {
const httpOptions = {
headers: new HttpHeaders({
'Content-type ': 'application/json',
'Acces-Control-Allow-Origin': '/*'
})
}
return this.http.post<Prestation>(this.SAVE_PRESTA, prestation, httpOptions).pipe(
tap(_ => this.log(`save prestation with id = ${prestation.id}`)),
catchError(this.handleError<any>('addPresta'))
);
}
here is my angular method savePresta
savePresta() {
const uploadData = new FormData();
uploadData.append('imageFile', this.selectedFile, this.selectedFile.name);
this.selectedFile.imageName = this.selectedFile.name;
this.http.post(this.SAVE_PRESTA + '/upload', uploadData, { observe: 'response' }).subscribe(
(response) => {
if (response.status == 200) {
this.service.savePrestation(this.prestation).subscribe(
(prestation) => {
this.prestation = prestation;
this.goBack();
});
console.log('image uploaded successfull');
} else {
console.log('image not uploaded sucessfull')
}
});
}
I still have the same error
Access to XMLHttpRequest at 'http://localhost:8080/prestations' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
POST http://localhost:8080/prestations net::ERR_FAILED
ERROR HttpErrorResponse headers: HttpHeaders status: 0 statusText: "Unknown Error" url:"http://localhost:8080/prestations", ok: false …
help me please that days that I block the top I tried everything but nothing helped
It is a CORS problem, related to a security issue.
The problem
Suppose that your frontend is hosted on xxx.com and the backend is on yyy.com.
From the browser point of view, you are connected to xxx.com but issue requests to yyy.com, which is weird. If yyy.com does not explicitly authorizes to send request from xxx.com, the browser will block the request.
Now, how does the browser knows that yyy.com authorizes requests from xxx.com ? With a pre-flight request. The browser executes a pre-flight request and expect to find some CORS related HTTP headers in the response. See ? This is what is written in the error message: Response to preflight request doesn't pass access control check
Here is an example of such HTTP headers :
Access-Control-Allow-Origin: http://toto.example
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Here, localhost:4200 and localhost:8080 are considered as 2 different origins
What can you do ?
You have 2 solutions : create a proxy OR set correct HTTP headers
Create a proxy
Suppose that you create a proxy on zzz.com. Your browser is connected to zzz.com, and all backend calls are made to zzz.com. From your browser point of view, there are no more cross origin resources sharing.
But, zzz.com has to redirect frontend requests to xxx.com and backend requests to yyy.com. This can easily be done if you decide that all your backend requests start with something like /api. This will allow you to write a simple regex :
/api => backendFortunately, in dev environment, Angular provides a built-in solution for that. You can take a look at Proxying to a backend server
It merely consist of starting the angular app with the --proxy-config option pointing to a file such as :
{
"/api": {
"target": "http://localhost:8080",
"secure": false
}
}
(Here, we suppose that all your backend endpoints start with /api)
HTTP Headers
This answer provides a solution with some Angular conf : How to resolve the CORS issue using proxy in angular
Never ever use Access-Control-Allow-Origin: *
If you want to easily modify HTTP Headers for test purposes, you can install the Chrome extension modHeader
Note : you will have exactly this problem when you go to production so the solution choice must be driven by the solution you need in production.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With