1. Basic CORS concept
1.1 What is cross-domain request
Cross-Origin Resource Sharing (CORS) is a security mechanism that allows web applications to request resources on one domain on another domain. For security reasons, browsers will block AJAX requests between different sources, which is a limitation of the **Same-Origin Policy (Same-Origin Policy).
1.2 Definition of homologous policy
The conditions for two URLs to be considered homologous:
- The protocol is the same (http/https)
- The domain name is the same
- Same port
For example:
- /app1 and /app2 → Same source
- and → different sources (different protocols)
- and → different sources (domain names are different)
- And :8080 → Different sources (different ports)
2. 5 ways Spring Boot handles CORS
2.1 Global Configuration (Recommended)
Method 1: Use WebMvcConfigurer interface
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { ("/**") // All interfaces .allowedOrigins("*") // All sources are allowed .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // Allow method .allowedHeaders("*") // All headers are allowed .allowCredentials(true) // Allow credentials .maxAge(3600); // Preflight request cache time } }
Method 2: Use Filter method (suitable for Servlet applications)
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); (true); ("*"); ("*"); ("*"); ("/**", config); return new CorsFilter(source); }
2.2 Controller method level configuration
Method 3: Use @CrossOrigin annotation
@RestController @RequestMapping("/api") public class UserController { // Single method configuration @CrossOrigin(origins = "http://localhost:3000") @GetMapping("/users") public List<User> getUsers() { // ... } // The entire controller configuration @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/products") public class ProductController { // ... } }
2.3 Properties file configuration (Spring Boot 2.4+)
Method 4: Configure
spring: mvc: cors: allowed-origins: "http://localhost:3000, " allowed-methods: "GET, POST, PUT, DELETE" allowed-headers: "*" exposed-headers: "Authorization, Content-Disposition" allow-credentials: true max-age: 1800
Equivalent:
-origins=http://localhost:3000, -methods=GET, POST, PUT, DELETE -headers=* -headers=Authorization, Content-Disposition -credentials=true -age=1800
2.4 Manual setting of response headers
Method 5: Add response headers manually (flexible but cumbersome)
@RestController public class ApiController { @GetMapping("/manual") public ResponseEntity<String> manualCors() { return () .header("Access-Control-Allow-Origin", "*") .header("Access-Control-Allow-Methods", "GET") .body("Manual CORS configured"); } }
3. In-depth analysis of CORS processing
3.1 Preflight Request
For "non-simple request", the browser will first send an OPTIONS preflight request:
Simple request conditions:
1. Use GET, HEAD or POST methods
2. Only include the following headers:
- Accept
- Accept-Language
- Content-Language
- Content-Type (only application/x-www-form-urlencoded, multipart/form-data, text/plain)
Non-simple request example:
fetch('/data', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-Custom-Header': 'value' }, body: ({key: 'value'}) });
Spring Boot will automatically process OPTIONS requests without the need for additional encoding by developers.
3.2 Core response header description
Response header | illustrate |
---|---|
Access-Control-Allow-Origin | The source allowed to access,* Indicates any source |
Access-Control-Allow-Methods | Allowed HTTP methods |
Access-Control-Allow-Headers | Allowed request header |
Access-Control-Expose-Headers | Response header that allows browser access |
Access-Control-Allow-Credentials | Whether to allow sending cookies and HTTP authentication information |
Access-Control-Max-Age | Cache time of pre-check request result (seconds) |
3.3 Frequently Asked Questions
Question 1: AllowCredentials(true) conflicts with allowedOrigins("*")
mistake:
When allowCredentials is true, allowedOrigins cannot contain the special value "*"
Solution:
// Replace with specific domain name.allowedOrigins("http://localhost:3000", "")
Question 2: The front-end still reports CORS error
Check steps:
- Make sure the backend is configured correctly
- Check browser console error details
- Use Postman and other tools to verify that the interface is working properly
- Check if multiple CORS configurations are overwhelmed
Question 3: Custom filter interferes with CORS
Solution:
Ensure CorsFilter priority in filter chain:
@Bean public FilterRegistrationBean<CorsFilter> corsFilterRegistration() { FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(); (corsFilter()); (Ordered.HIGHEST_PRECEDENCE); // Highest priority return registration; }
4. Safety best practices
4.1 Production environment configuration suggestions
@Configuration public class ProdCorsConfig implements WebMvcConfigurer { @Value("${-origins}") private String[] allowedOrigins; @Override public void addCorsMappings(CorsRegistry registry) { ("/api/**") .allowedOrigins(allowedOrigins) .allowedMethods("GET", "POST") .allowedHeaders("Content-Type", "Authorization") .exposeHeaders("X-Custom-Header") .allowCredentials(true) .maxAge(3600); } }
4.2 Combined with Spring Security
When using Spring Security, you need to make sure that CORS is configured before the security filter:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { ().and() // Enable CORS support for Spring Security .csrf().disable() .authorizeRequests() // Other configurations... } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); (("")); (("GET", "POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); ("/**", configuration); return source; } }
4.3 Monitoring and logging
Add CORS request log:
@Bean public FilterRegistrationBean<CorsFilter> corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // ...Configuration FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(); (new CorsFilter(source) { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ("CORSask: {} {}", (), ()); (request, response, filterChain); } }); return registration; }
V. Testing and Verification
5.1 Test class example
@SpringBootTest @AutoConfigureMockMvc public class CorsTest { @Autowired private MockMvc mockMvc; @Test public void testCorsHeaders() throws Exception { (options("/api/users") .header("Access-Control-Request-Method", "GET") .header("Origin", "http://localhost:3000")) .andExpect(header().exists("Access-Control-Allow-Origin")) .andExpect(header().string("Access-Control-Allow-Methods", "GET")); } @Test public void testActualRequest() throws Exception { (get("/api/users") .header("Origin", "http://localhost:3000")) .andExpect(status().isOk()) .andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:3000")); } }
5.2 Testing with CURL
Check OPTIONS preflight request:
curl -X OPTIONS http://localhost:8080/api/users \
-H "Origin: " \
-H "Access-Control-Request-Method: GET" \
-I
Check the actual request:
curl -X GET http://localhost:8080/api/users \
-H "Origin: " \
-I
6. Summary and Recommended Plan
6.1 Configuration method comparison
Way | Applicable scenarios | advantage | shortcoming |
---|---|---|---|
Global WebMvcConfigurer | Most applications | Centralized management, support fine-grained configuration | Need code changes |
Filter method | Need the highest priority | The earliest processing is to avoid being interfered by other filters | A little more complex configuration |
@CrossOrigin annotation | Specific interfaces require special rules | Precise control | Spread all over the place, with high maintenance costs |
Properties file configuration | Simple requirements, configuration driver | No code changes required | Low flexibility |
Manually set the response header | Need to dynamically determine the CORS header | Maximum flexibility | Highly invasive code |
6.2 Recommended plan
New Project:
- Global configuration using WebMvcConfigurer
- Dynamically configure the allowed sources in conjunction with attribute files
- Use @CrossOrigin to override global settings for special interfaces
Already project migration:
- Add global configuration first
- Gradually remove scattered annotation configurations
- Finally, unify 1-2 management methods
Spring Cloud Microservices:
- Unified processing of CORS in API Gateway
- Each microservice disables CORS or only allows gateway sources
- Combined with OAuth2 and other security mechanisms
6.3 Ultimate Suggestions
Do not use * as an allowable source in production - explicitly list trusted domain names
Limit allowed methods and headers - Configure according to the principle of least permissions
Set maxAge reasonably - balance safety and performance (1 hour recommended)
Collaborate with the front-end team - Ensure that both parties are consistent in their understanding of CORS requirements
Monitor CORS errors - promptly detect configuration problems or malicious requests
By rationally configuring CORS, it is possible to ensure security while providing necessary cross-domain support for modern front- and back-end separation architectures. Spring Boot provides a variety of flexible ways, and developers should choose the most suitable solution according to the actual needs of the project.
This is the article about this comprehensive guide to handling cross-domain requests for CORS in SpringBoot. For more relevant SpringBoot cross-domain requests for CORS, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!