手机扫一扫访问本页内容

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

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

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

关闭
经验 ,

加SSL的SpringBoot项目用https访问出现CORS跨域问题

问题是这样的,我用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字符串。

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

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);
}

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

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


展开阅读全文


上一篇:

下一篇:

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