I am doing a react app with spring boot for the back end and mysql as the database. Its a simple CRUD of notes, but I am having a problem when fetching from the API to execute the methods. When I send a request through postman i have no errors, and I can see the note added in the database, but when going through the web app, I get an error. I have very little idea how to fetch data from an api with react, I was just following a tutorial and modifying a bit for my project. I know there are also things like await but don’t know if the problem is that I didn’t use that. I get the following error
Access to fetch at 'http://localhost:8080/api/note' from origin 'http://localhost:3000' 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. If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
POST http://localhost:8080/api/note net::ERR_FAILED
Uncaught (in promise) TypeError: Failed to fetch
Here is my code.
Controller class
@RestController
@RequestMapping(path = "api/note")
@CrossOrigin(origins = "*")
public class NoteController {
@Autowired
NoteService noteService;
@PostMapping(path = "/")
public ResponseEntity<NoteModel> createNote(@RequestBody NoteModel newNote) {
return new ResponseEntity<>(this.noteService.createNote(newNote), HttpStatus.OK);
}
@PutMapping(path = "/{id}")
public ResponseEntity<NoteModel> updateNote(@RequestBody NoteModel note, @PathVariable Long id) throws Exception {
return new ResponseEntity<>(this.noteService.updateNote(note, id), HttpStatus.OK);
}
@GetMapping(path = "/")
public ResponseEntity<List<NoteModel>> findAllNotes(){
return new ResponseEntity<>(this.noteService.findAllNotes(), HttpStatus.OK);
}
@DeleteMapping(path = "/{id}")
public ResponseEntity<String> createNote(@PathVariable Long id) throws Exception {
this.noteService.deleteNote(id);
return new ResponseEntity<>("Note deleted successfully", HttpStatus.CREATED);
}
}
React component doing the fetching.
import React from 'react'
import closeButton from '../images/close-button.png'
import { useState } from 'react';
function Popup(props) {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const handleClick=(e) => {
e.preventDefault()
const note = {title, content}
console.log(title, content)
fetch("http://localhost:8080/api/note", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(note)
}).then(()=>{
console.log("New note added!")
})
setTitle("")
setContent("")
props.setTrigger(false)
}
const handleExit=(e) => {
e.preventDefault()
props.setTrigger(false)
setTitle("")
setContent("")
}
return (props.trigger) ? (
<div className="popup">
<div className="inner-popup">
<img src={closeButton} className="close-btn" onClick={handleExit} alt="Close"/>
<h2 className="popup-title">Add new note</h2>
<form>
<div className="form-title">
<label>Title</label>
<input
type="text"
id="form-title-input"
name="form-title-input"
placeholder="Note Title"
value={title}
onChange={(e)=>setTitle(e.target.value)}
/>
</div>
<div className="form-content">
<label>Content</label>
<textarea
id="note-content-txtf"
name="note-content"
placeholder="Note about something..."
value={content}
onChange={(e)=>setContent(e.target.value)}
/>
</div>
<div className="form-buttons">
<button className="btn box-shw btn-cancel" onClick={handleExit}>Cancel</button>
<button className="btn box-shw btn-confirm" onClick={handleClick}>Confirm</button>
</div>
</form>
</div>
</div>
) : "";
}
export default Popup
I tried adding @CrossOrigin(origins="*")
to the controller class in java, still didnt work. Disabling cors with mode: "no-cors" in the react app when fetching made the error not appear, but it still didnt POST. Tried adding CorsConfiguration class in java still no luck. Also tried adding Access-Control-Allow-Origin: "*"
to the headers in the fetch on the react app, but still doesn’t work. I have no idea what else I can try so if anybody can give me a hand I would appreciate it.
2
Answers
You can try with some changes in your current implementation as shown below:
@CrossOrigin at the Class Level with maxAge.
since maxAge = 3600, all pre-flight responses will be cached for 60
mins.:
Enabling CORS Globally
Instead of adding CORS to each of the resources separately, we can define a common CORS configuration that would apply to all defined resources.You can use a
WebMvcConfigurer
,by overriding theaddCorsMapping()
method you can configure CORS to all URLs.You can create a@Bean
and include this code in your main class.If you created the React project using CRA, then add the following to package.json:
If you are using vite then you can add the following to vite.config.js