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:

@CorsOrigin source code

CorsConfiguration source code

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() {} 
}