Create Cross-Origin requests (CORS)
During the development of your application it is a good practice to work with 2 separate server. A server for your backend and a server for your frontend.
Your JavaScript frontend will communicate with your backend to collect information using REST services.
At this moment you will incur in a problem : for security reasons browsers don’t allow that a page answering from the domainA load resources from a domainB.
How CORS works
You can read the detailed explanation of the CORS mechanism here: Mozilla
To summarize, the browser for security reasons must enforce the Same-Origin-Policy. By default, it won't allow your website: http://mywebsite.com to access resources of a different website if not explicitly allowed.
To define if the origin is the same the browser use the scheme, host and port of the server e.g.: http://mydomain.com has a different host of : http://api.mydomain.com for this reason the requests will be blocked.
When you try to access a different domain, the browser send a pre-flight request with OPTIONS to get information from the target server. If the target server responds with Access-Control-Allow-Origin: http://mydomain.com
in the headers, your browser will send requests to it.
How to allow CORS requests
Angular
In our Angular request, if we don't use the HttpClient that comes with the framework, we have to add the header
X-Requested-With. This header enables a webpage to update just partially.
this.headers = new Headers({ 'Content-Type': 'application/json' })
this.headers.append('Accept', 'application/json, text/csv');
this.headers.append('X-Requested-With', 'XMLHttpRequest');
The same solution works for React and Vue.js projects.
Spring Boot
Building a Spring application with a web client when you deploy the application on 2 different servers or ports you could get this error when you try a REST call:
Access to XMLHttpRequest at '[url]' from origin '[url]' 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.
By default, for security reasons, the application server doesn't allow that clients running in other machines / on other ports use your service without authorization.
For an intranet / secured network application you can simply allow all the request to be executed
With @CrossOrigin annotation
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin("*")
public class FoodController {
The * accepts requests from every origin, for production environments you have to fine tune this parameter.
To see in the detail the feature:
Without annotations
You have to update the ALLOWED_ORIGINS
constant with the URL of the frontend server sending the requests to the backend server.
@Configuration
public class CorsConfig {
private static final String[] ALLOWED_ORIGINS = {"https://localhost:3000",
"https://localhost:8080"};
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*").allowedOrigins(ALLOWED_ORIGINS);
}
};
}
}
Java EE
Filter
The filter solution can be used in Servlet compatible Servers.
@Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {
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, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization,Content-Type, x-requested-with");
response.setHeader("Access-Control-Max-Age", "3600");
if (((HttpServletRequest)req).getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}