When developing web applications, you’ll often run into CORS (Cross-Origin Resource Sharing) errors when your frontend (React JS) and backend (Spring Boot) are running on different origins (i.e., different ports or domains). This happens because modern browsers block requests made across different domains for security reasons unless the server allows it. In this article, we will address a common CORS error you might face while working with React JS and Spring Boot.
CORS Error in React JS and Spring Boot Integration
You may encounter the following error when calling a DELETE service from React JS to Spring Boot backend using Axios:
Access to XMLHttpRequest at 'http://localhost:8080/testdelete' 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.
This error occurs because the server (Spring Boot) hasn’t been configured to allow cross-origin requests from your React app, which is running on http://localhost:3000
. The browser is blocking this request due to the absence of the appropriate headers in the response.
Setting up CORS in Spring Boot
To resolve this issue, we need to configure Spring Boot to allow cross-origin requests. Here’s how you can handle this in the Spring Boot application.
Spring Boot Controller Code with CORS Configuration
In your Spring Boot controller, you can add the @CrossOrigin
annotation to allow requests from specific origins. For example:
@CrossOrigin(origins = "http://localhost:3000", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.OPTIONS})
@RestController
public class TestDelete {
@DeleteMapping("/testdelete")
public ResponseEntity<Void> deleteData(@RequestBody Data data) throws Exception {
// Your logic to delete data
return ResponseEntity.noContent().build();
}
}
Explanation of the @CrossOrigin
Annotation:
origins
: Specifies the allowed origin(s) (in this case,http://localhost:3000
where your React app is running). You can specify a list of origins if you have more than one frontend URL.methods
: Defines which HTTP methods are allowed. We’ve listedGET
,POST
,DELETE
, andOPTIONS
because you may use them in your application.
The @CrossOrigin
annotation tells Spring Boot to include the necessary CORS headers in the response, such as:
Access-Control-Allow-Origin
: Specifies which origins are allowed to access the resource.Access-Control-Allow-Methods
: Specifies which HTTP methods are allowed for cross-origin requests.Access-Control-Allow-Headers
: Specifies which headers are allowed in the request.
React JS Code with Axios
Your React JS code is making a DELETE request to the backend, but you’re manually setting some of the CORS-related headers in the Axios request. While the backend should already handle the CORS headers properly (via @CrossOrigin
), you don’t need to set Access-Control-Allow-Headers
, Access-Control-Allow-Origin
, and Access-Control-Allow-Methods
in the Axios request. The browser will handle them automatically.
Here’s the updated React code:
axios({
method: 'DELETE',
url: `http://localhost:8080/testdelete`,
data: data,
headers: {
'Content-Type': 'application/json',
}
})
Key Points:
- No need to manually set CORS headers in the request: The CORS headers (
Access-Control-Allow-Origin
, etc.) should be managed by the Spring Boot server. - Correct usage of
@CrossOrigin
: Ensure that the@CrossOrigin
annotation is applied at the method level (as shown) to allow the DELETE method.
Additional Steps to Ensure Correct CORS Setup
Global CORS Configuration
If you want to configure CORS globally across your entire Spring Boot application (for all controllers), you can do this by creating a WebMvcConfigurer
bean. This way, you don’t have to add @CrossOrigin
on each individual controller or method.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "DELETE", "OPTIONS");
}
}
This configuration ensures that all requests from http://localhost:3000
are allowed to access any endpoint in your Spring Boot application.
Using @CrossOrigin
at Class Level
You can also apply @CrossOrigin
at the class level to apply it to all the methods within that class. This is helpful when you want all endpoints in a specific controller to allow cross-origin requests from a certain origin.
@CrossOrigin(origins = "http://localhost:3000", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.OPTIONS})
@RestController
public class TestDelete {
// All methods in this class will have the CORS configuration
}
React Development Server Proxy Setup
Sometimes, especially during development, it’s a good idea to set up a proxy for React JS to bypass CORS issues without configuring CORS headers in the backend. You can add this to your package.json
file in the React app:
"proxy": "http://localhost:8080",
This configuration makes requests from localhost:3000
automatically proxy through to localhost:8080
, avoiding CORS issues during development.
Final Thoughts
Now that your CORS error is resolved, you can start adding more functionality to your application. Here are some extra features to try adding:
- Add Error Handling in React: Improve your frontend by handling errors such as timeouts or failed requests.
axios({
method: 'DELETE',
url: `http://localhost:8080/testdelete`,
data: data,
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
console.log("Data deleted successfully");
})
.catch(error => {
console.error("Error deleting data:", error);
});
- Implement Pagination for Data Retrieval: If you’re dealing with large datasets, consider adding pagination to your backend and frontend.
- Enhance Security with CSRF Protection: CORS is important, but security should also be a priority. Consider enabling CSRF protection to prevent malicious attacks.
- Optimizing Axios Requests: Use interceptors in Axios to handle common logic for each request, such as adding authentication tokens to the request headers.