手机扫一扫访问本页内容

微信扫描点右上角"···"分享到好友或朋友圈

关闭
微信扫一扫可打开小程序

微信长按图片或搜“分享录”可打开小程序

关闭
经验 ,

基于SpringBoot后台项目跨域问题解决方案

问题是这样的,我用SpringBoot在服务器上搭了一个新的微服务,在本地调试遇到跨域问题加个CorsFilter拦截器Bean就解决,但升到服务器上却仍然报跨域问题:“Access to XMLHttpRequest at ‘https://xxx.xubingtao.cn/xxx’ from origin ‘https://www.xubingtao.cn’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”或“Access to XMLHttpRequest at ‘https://xxx.xubingtao.cn/xxx’ from origin ‘https://www.xubingtao.cn’ 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.”

我就在想是不是我域名加SSL证书的原因,到网上找到很多资料,各种解决方案如下。

有说在静态页面加入:

<meta http-equiv="Access-Control-Allow-Origin" content="*" />
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

异步js:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('GET', 'https://www.xubingtao.cn/', true);
xhr.onreadystatechange = function() {
  console.log('withCredentials=>', xhr.withCredentials);
};
xhr.send(null);

异步jquery:

$.ajax({
            url: "https://www.xubingtao.cn/",
            type: "GET",
            xhrFields: {
                withCredentials: true
            },
            crossDomain: true,
            success: function (data) {
                render(data);
            }
 });

nginx各种配置方式:

代码如下:

#add_header 'Access-Control-Allow-Origin' '*'; #$http_origin;
		#add_header 'Access-Control-Allow-Credentials' 'true';
		#add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
		#add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
		#add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
		#if ($request_method = 'OPTIONS') {
		#	add_header 'Access-Control-Max-Age' 1728000;
		#	add_header 'Content-Type' 'text/plain; charset=utf-8';
		#	add_header 'Content-Length' 0;
		#	return 204;
		#}
####################################
#if ($request_method = 'OPTIONS') {
             #   add_header 'Access-Control-Allow-Origin' '*';
             #   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             #   add_header 'Access-Control-Allow-Headers' '*';
             #   add_header 'Access-Control-Max-Age' 1728000;
             #   add_header 'Content-Type' 'text/plain charset=UTF-8';
             #   add_header 'Content-Length' 0;
             #   return 204;
             #}
             #if ($request_method = 'POST') {
             #   add_header 'Access-Control-Allow-Origin' '*';
             #   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             #   add_header 'Access-Control-Allow-Headers' '*';
             #}
             #if ($request_method = 'GET') {
             #   add_header 'Access-Control-Allow-Origin' '*';
             #   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             #   add_header 'Access-Control-Allow-Headers' '*';
             #}
####################################
#add_header Access-Control-Allow-Origin *;
	     #add_header Access-Control-Allow-Headers X-Requested-With;
  	     #add_header Access-Control-Allow-Methods GET,POST,OPTIONS;

甚至还找到PHP版的,在Wordpress的主题下functions.php中加以下配置:

function add_custom_headers() {
    add_filter( 'rest_pre_serve_request', function( $value ) {
        header( 'Access-Control-Allow-Headers: Authorization, X-WP-Nonce,Content-Type, X-Requested-With');
        header( 'Access-Control-Allow-Origin: *' );
        header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
        header( 'Access-Control-Allow-Credentials: true' );
        return $value;
    } );
}
add_action( 'rest_api_init', 'add_custom_headers', 15 );

Java的处理方式有,在要调用controller加@CrossOrigin注解、加Filter拦截器、实现WebMvcConfigurer重写addCorsMappings等。

加Filter拦截器:

//@Component
@WebFilter(filterName = "corsFilter", urlPatterns = {"/*"})
public class CorsFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp;
        response.setHeader("Access-Control-Allow-Origin", "*");
	response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
//        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        response.setHeader("Access-Control-Allow-Headers", "*");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig filterConfig) {
    }

    public void destroy() {
    }
}

实现WebMvcConfigurer重写addCorsMappings:

@Configuration
public class CorsConfigures implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        System.out.println("-----------------------addCorsMappings--------------------------");
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOrigins(CorsConfiguration.ALL)
                .allowedMethods(CorsConfiguration.ALL)//("POST", "GET", "DELETE", "PUT", "HEAD", "OPTIONS")
                .allowedHeaders(CorsConfiguration.ALL)
//                        "Access-Control-Allow-Origin", "Content-Type", "x-requested-with", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Pragma")
                .exposedHeaders(//这个不支持*
                        "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Access-Control-Allow-Credentials", "Pragma")
                // 最大过期时间,单位秒,默认是1800
                .maxAge(3600);
    }

//    @Bean
//    public FilterRegistrationBean corsFilter() {
//        System.out.println("-----------------------FilterRegistrationBean--------------------------");
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        CorsConfiguration config = new CorsConfiguration();
//        config.setAllowCredentials(true);
//        // 设置你要允许的网站域名,如果全允许则设为 *
//        config.addAllowedOrigin(CorsConfiguration.ALL);
//        // 如果要限制 HEADER 或 METHOD 请自行更改
//        config.addAllowedHeader(CorsConfiguration.ALL);
//        config.addAllowedMethod(CorsConfiguration.ALL);
//        source.registerCorsConfiguration("/**", config);
//        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
//        // 这个顺序很重要哦,为避免麻烦请设置在最前
//        bean.setOrder(0);
//        return bean;
//    }
}

需要注意的是,上面的exposedHeaders不支持直接配*,而且所有参数都是String类型多参数(如“String… origins”)而不是直接传一个String字符串。下面截图是基于springboot 2.3.0.RELEASE版本,我看新版本已经支持配*了,具体大家可以打开源码看是否支持。

但你会发现加了一堆乱七八糟的配置,还是报各种跨域问题!

Provisional headers are shown:

Access to XMLHttpRequest at ‘https://www.xxxx.com’ from origin ‘http://192.168.1.4’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘http://192.168.1.4, *’, but only one is allowed.这个问题的原因是服务器设置了两次跨域,有可能是nginx设置了一次,服务端代码又设置了一次,只需要设置一次就可以。

没错,我把Nginx、前端的各种配置去掉后果然没报跨域问题了。实际上这个跨域问题只需要在被访问的一端配就行了,经测试在nginx配置不起作用,在Java后台服务有多种方式可以解决跨域问题,包括在要调用controller加@CrossOrigin注解可以解决跨域问题(这种方式要每个controller都加注解不方便,为了安全起见最好加origins = “https://www.xubingtao.cn”限制域),另外还有以下几种也是可以解决跨域问题的:

有效方式一:

@Configuration
public class CorsConfigures implements WebMvcConfigurer {
@Override
    public void addCorsMappings(CorsRegistry registry) {
        System.out.println("-----------------------addCorsMappings--------------------------");
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOrigins("https://www.xubingtao.cn")
                .allowedMethods(CorsConfiguration.ALL)//("POST", "GET", "DELETE", "PUT", "HEAD", "OPTIONS")
                .allowedHeaders(CorsConfiguration.ALL)
//                        "Access-Control-Allow-Origin", "Content-Type", "x-requested-with", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Pragma")
                .exposedHeaders(//这个不支持*
                        "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Access-Control-Allow-Credentials", "Pragma")
                // 最大过期时间,单位秒,默认是1800
                .maxAge(3600);
    }
}

有效方式二:新建个带@Configuration注解或直接在启动来加下面的bean:

@Bean
public FilterRegistrationBean corsFilter() {
    System.out.println("-----------------------FilterRegistrationBean--------------------------");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    // 设置你要允许的网站域名,如果全允许则设为 *
    config.addAllowedOrigin("https://www.xubingtao.cn");
    // 如果要限制 HEADER 或 METHOD 请自行更改
    config.addAllowedHeader(CorsConfiguration.ALL);
    config.addAllowedMethod(CorsConfiguration.ALL);
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    // 这个顺序很重要哦,为避免麻烦请设置在最前
    bean.setOrder(0);
    return bean;
}

有效方式三:新建个带@Configuration注解或直接在启动来加下面的bean:

@Bean
public CorsFilter corsFilter() {
	CorsConfiguration corsConfiguration = new CorsConfiguration();
	corsConfiguration.addAllowedOrigin("https://www.xubingtao.cn");
	corsConfiguration.addAllowedHeader("*");
	corsConfiguration.addAllowedMethod("*");
	corsConfiguration.addExposedHeader("Access-Control-Allow-Origin");
	UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
	source.registerCorsConfiguration("/**", corsConfiguration);
	return new CorsFilter(source);
}

需要注意的是,带“www”与否会被判定为不同的域名,所以要在corsConfiguration.addAllowedOrigin中加入两次该顶级域名。

简单了解一下CORS,CORS全称是”跨域资源共享”(Cross-origin resource sharing),是一个W3C标准,它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,以避开浏览器的同源策略,是 JSONP 模式的现代版。JSONP只支持GET请求,CORS支持GET方法外也支持其他的 HTTP 请求。用 CORS 可以让XMLHttpRequest的错误处理比 JSONP 好。不过JSONP可以在不支持 CORS 的旧浏览器上运行。

更多关于跨域资源共享,可以访问这篇文章《跨域资源共享 CORS 详解》。

最后我们弄清了问题是由浏览器跨域问题造成的跟域名是否加证书没有关系,所以我把之前的文章名由《加SSL的SpringBoot项目用https访问出现CORS跨域问题》改成《基于SpringBoot后台项目跨域问题解决方案》。


展开阅读全文


上一篇:

下一篇:

服务器又要到期了鼓励一下吧
您还可以访问本站的小程序、公众号等所有端,或者下载APP, 在小程序、APP上可以评论文章以及保存图片还有在线客服哦,如您有任何疑问或建议可向作者提出意见反馈
扫码打开小程序可评论文章保存图片,在“我的”有实时在线客服哦,看效果?
关注我的公众号为您分享各类有用信息
分享录多端跨平台系统