Mastering CORS in Spring: 5 Ways to Enable Cross‑Origin Requests
This article explains why browsers enforce the same‑origin policy, defines cross‑origin requests, outlines the restrictions of non‑same‑origin interactions, and presents five practical methods—including a global CorsFilter, WebMvcConfigurer, @CrossOrigin annotation, manual header setting, and a custom filter—to implement CORS in Java Spring backends.
Why CORS Issues Occur
The browser enforces a same‑origin policy . A script can only read cookies, local storage, IndexedDB, or make AJAX calls to resources that share the same protocol, host, and port as the page that loaded the script. When a request targets a different origin, the browser blocks the response unless the server explicitly permits the cross‑origin access via CORS headers.
What Constitutes a Cross‑Origin Request
A request is cross‑origin when any of the three components—protocol, domain, or port—differs from those of the page that initiated the request.
Restrictions Imposed by the Same‑Origin Policy
Scripts cannot read cookies, LocalStorage, or IndexedDB belonging to another origin.
Scripts cannot access the DOM of a page served from a different origin.
Scripts cannot send AJAX (XHR/fetch) requests to a different origin unless the server returns the appropriate CORS response headers.
Five Common Ways to Enable CORS in a Spring‑based Java Backend
Register a global CorsFilter bean.
Implement WebMvcConfigurer and override addCorsMappings.
Apply the @CrossOrigin annotation on controller classes or individual handler methods.
Manually add the required headers via HttpServletResponse.
Create a custom servlet filter that sets the CORS headers and configure it in web.xml.
1. Global CorsFilter Bean
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
// 1. Define the CORS policy
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*"); // allow any origin
config.setAllowCredentials(true); // include cookies
config.addAllowedMethod("*"); // allow all HTTP methods
config.addAllowedHeader("*"); // allow all request headers
config.addExposedHeader("*"); // expose all response headers
// 2. Map the policy to URL patterns
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
// 3. Return the filter instance
return new CorsFilter(source);
}
}2. Override WebMvcConfigurer
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.exposedHeaders("*");
}
}3. Use @CrossOrigin Annotation (Local CORS)
On a controller class (applies to all handler methods):
@RestController
@CrossOrigin(origins = "*")
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello world";
}
}On a single method (more granular control):
@RequestMapping("/hello")
@CrossOrigin(origins = "*")
public String hello() {
return "hello world";
}4. Manually Set Response Headers (Local CORS)
@RequestMapping("/index")
public String index(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
// Optional: add other CORS headers such as Access-Control-Allow-Methods, etc.
return "index";
}5. Custom Servlet Filter Implementation (Local CORS)
Define a filter class that adds the required CORS headers to every response.
package com.mesnac.aop;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
@Component
public class MyCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
chain.doFilter(req, res);
}
@Override public void init(FilterConfig filterConfig) {}
@Override public void destroy() {}
}Configure the filter in web.xml (the XML tags are escaped so they are not parsed as HTML):
<!-- CORS START -->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>com.mesnac.aop.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- CORS END -->Key Takeaways
All approaches ultimately add the required Access-Control-* response headers so that browsers accept cross‑origin responses.
Global configurations ( CorsFilter bean, WebMvcConfigurer) affect every endpoint, while @CrossOrigin, manual header setting, and custom filters can be scoped to specific controllers or methods.
Spring MVC 4.2+ (Spring Boot 1.3+) is required for the built‑in CORS support.
When both global and local CORS settings are present, the more specific (local) configuration overrides the global one.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
