Cross-Origin Issue Description
You might encounter the following error message:
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
This error indicates that a request to a certain address has been blocked by the CORS protocol because the Access-Control-Allow-Origin
header is missing from the resource.
Analyzing Cross-Origin Issues
The root cause of cross-origin issues is that browsers, for security reasons, restrict access to resources outside the current site.
For example, consider a website hosted at http://127.0.0.1:8080/
with a certain page. If you access resources from the same site, there are no restrictions. But if you try to access resources from a different site (e.g., http://127.0.0.1:8081
), the browser will block the request.
Note: We consider protocol, domain, and port as part of defining a "same-origin."
Elements with a src
attribute, like img
and script
tags, are not subject to this restriction.
Historically, when front-end and back-end were not separate, pages and request interfaces existed under the same domain and port. Browsers would then allow requests from a page hosted at one domain to request resources from the same domain.
For example, http://127.0.0.1:8080/index.html
can freely request http://127.0.0.1:8080/a/b/c/userLit
.
Nowadays, with the front-end and back-end separated into different applications, this isn't allowed and will trigger CORS issues.
What is Origin and Cross-Origin?
Origin (or source) consists of the protocol, domain, and port number.
A URL is composed of protocol, domain, port, and path. Two URLs are considered "same-origin" if their protocol, domain, and port are all identical. Any difference in any of these three elements constitutes a cross-origin request.
Consider cross-origin comparisons for https://www.baidu.com/index.html
:
URL | Cross-Origin | Reason |
---|---|---|
https://www.baidu.com/more/index.html | No | Same protocol, domain, and port |
https://map.baidu.com/ | Yes | Different domain |
http://www.baidu.com/index.html | Yes | Different protocol |
https://www.baidu.com:81/index.html | Yes | Different port |
What is the Same-Origin Policy?
The Same-Origin Policy is a fundamental browser security feature. Without it, the normal functionality of browsers could be at risk. Web architecture heavily depends on this policy, and browsers implement it to ensure security.
The Same-Origin Policy includes:
-
DOM Same-Origin Policy: Prevents DOM manipulation of different origin pages. Applies mainly to cross-origin
iframe
scenarios where different domains'iframes
can't access each other. - XMLHttpRequest Same-Origin Policy: Prohibits HTTP requests to different origins using XHR objects.
Solving Cross-Origin Issues in Spring Boot
1. Creating a Filter to Handle CORS
In a project where the front-end and back-end are deployed separately, addressing CORS is crucial. Cookies are used to store user login information, and Spring interceptors manage permissions. Issues arise when the interceptor and CORS are processed in the wrong order, causing a CORS error.
An HTTP request first goes through the filter before reaching the servlet and then the interceptor. To ensure CORS processing occurs before authorization interception, we can place the CORS configuration in a filter.
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
2. Configuring CORS in WebMvcConfigurer
While JSONP can address cross-origin issues on the front-end, it only supports GET requests, which is limiting in RESTful applications. Instead, you can handle cross-origin requests with Cross-Origin Resource Sharing (CORS) on the back-end. This solution is not unique to Spring Boot and has been used in traditional SSM frameworks. You configure it by implementing the WebMvcConfigurer
interface and overriding the addCorsMappings
method.
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
3. Configuring CORS in Controller
You can enable CORS for specific controller methods by adding the @CrossOrigin
annotation to the @RequestMapping
annotation. By default, @CrossOrigin
allows all origins and HTTP methods specified in @RequestMapping
.
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
Understanding @CrossOrigin Parameters:
-
@CrossOrigin
without parameters allows all URLs to access. -
@CrossOrigin(origins = "http://127.0.0.1:8080")
restricts access to the specified URL. - This annotation can be used on classes or methods.
- The
value
ororigins
attribute specifies allowed URLs. -
maxAge
indicates the maximum age in seconds for the preflight request cache. -
allowCredentials
indicates if credentials (cookies) are allowed. Default isfalse
. -
allowedHeaders
specifies allowed request headers. -
methods
specifies allowed request methods, default being GET, POST, HEAD.
Reasons @CrossOrigin Might Not Work
- Spring MVC version must be 4.2 or higher to support
@CrossOrigin
. - Incorrect requests might appear as cross-origin issues due to improper server response.
- If adding
@CrossOrigin
above theController
annotation still results in issues, one possible fix is to specify the HTTP methods in@RequestMapping
.
Example:
@CrossOrigin
@RestController
public class PersonController {
@RequestMapping(method = RequestMethod.GET)
public String add() {
// some code
}
}
Top comments (0)