No 'access control allow origin' header: cross domain problem pit record

preface

When deploying a system on the server in the past two weeks, I encountered a cross domain problem. This is not the first time I encountered a cross domain problem. I thought it would be solved smoothly. I didn't expect to encounter many pits in the process of solving, so I think it's necessary to write a blog to record this pit.

Causes of problems

Originally, all applications in our group have a unified gateway service for interface request forwarding, and the relevant configurations have been completed. There is no cross domain problem. However, due to business expansion in the first two weeks, some applications need to be split and deployed to other servers, including the two applications I am responsible for.

Because one of the applications is a front-end and back-end project that is not separated, there is no cross domain problem, so the deployment is relatively smooth. Directly hit a jar package and throw it on the server. Another project is a front-end and back-end separation project. The process of jar package deployment is very smooth, but when I run the front-end with nginx, I see a pile of errors like the following figure:

This is a cross domain problem.

Solving process

1. Modify nginx configuration (not working)

The last time I encountered a cross domain problem, I solved it through nginx configuration proxy forwarding, so the first thing I thought of this time was to solve this problem by modifying the nginx configuration, so I added a configuration similar to this in the nginx configuration file:

server{
    listen 8888;
    server_name  192.168.1.100;

    location /{
        proxy_pass http://192.168.1.100:8080;
    }

    location /api{
        proxy_pass http://192.168.1.100:8081; //  All interface requests starting with api are forwarded here
}
}

However, it doesn't work. After that, I added some settings about the request header in the nginx configuration file, as shown below:

add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,HEAD,PUT';
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true'

Similarly, it did not solve the problem. At this point, I have temporarily abandoned the idea of solving cross domain problems by modifying the nginx configuration file.

2. Add cross domain processing configuration in backend code

I have also learned about how to solve cross domain problems at the back end. After checking the online information, the following two configuration classes are added to the code:

WebMvcConfig:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * Global processing interface Cross Domain
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
//                .allowedOrigins("*")
                // Most of the information on the Internet here is.allowedOrigins("*"),But because of my springboot Version 2.5.5,
                // allowCredentials by true Time and allowedOrigins Not null and empty ALL(this ALL namely*)An exception will be thrown
                // So what I set here is.allowedOriginPatterns("*")
                .allowedOriginPatterns("*")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .maxAge(3600)
                .allowCredentials(true);
    }
}

CORSFilter:

import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Global processing interface Cross Domain
 */
@Component
public class CORSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Credentials", "true");
        res.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
        res.setHeader("Access-Control-Allow-Headers", "*");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

}

I thought that with these two configuration classes, there was absolutely no problem with this one. Unfortunately, the problem still hasn't been solved.

However, after this deployment, the error message changed, suggesting that some request headers (such as client_id) failed to cross domains, which also gave me some inspiration.

3. Final solution

Finally, I will the following in the CORSFilter configuration class:

res.setHeader("Access-Control-Allow-Headers", "*");

Amend to read:

res.setHeader("Access-Control-Allow-Headers", "client_id, Authorization, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");

Then, it is packaged and deployed, and the cross domain problem is finally solved.

summary

After the problem was solved, I checked some data and found the following two knowledge points:

1. There are some special restrictions on the setting of access control allow origin request header. When the value of access control allow credentials is true, access control allow origin cannot be set to "*".

2. Because my spring boot version is relatively new, many cross domain configurations commonly used on the Internet are not suitable for me. such as   Access control allow headers cannot be directly set to *, but specific request headers need to be explicitly listed before they can take effect.

After tossing about for so long, I tried all kinds of methods on the Internet and didn't take effect, mainly because of the above two points. Fortunately, it was finally solved smoothly.

Tags: Spring Boot

Posted on Mon, 29 Nov 2021 22:45:30 -0500 by Edgewalker81