zoukankan      html  css  js  c++  java
  • SpringBoot 实现前后端分离的跨域访问(CORS)

    一、基本介绍

    简单来说,CORS是一种访问机制,英文全称是Cross-Origin Resource Sharing,即我们常说的跨域资源共享,通过在服务器端设置响应头,把发起跨域的原始域名添加到Access-Control-Allow-Origin 即可。

    1. CORS工作原理

    CORS实现跨域访问并不是一蹴而就的,需要借助浏览器的支持,从原理题图我们可以清楚看到,简单的请求(通常指GET/POST/HEAD方式,并没有去增加额外的请求头信息)直接创建了跨域请求的XHR对象,而复杂的请求则要求先发送一个”预检”请求,待服务器批准后才能真正发起跨域访问请求。

    根据官方文档W3C规范-CORS 的描述,目前CORS使用了如下头部信息。

    注:请求头信息由浏览器检测到跨域自动添加,无需过多干预,重点放在Response headers,它可以帮助我们在服务器进行跨域授权,例如允许哪些原始域可放行,是否需要携带Cookie信息等。

    2. Request Headers(请求头)

    • Origin:表示跨域请求的原始域。
    • Access-Control-Request-Method:表示跨域请求的方式。(如GET/POST)。
    • Access-Control-Request-Headers:表示跨域请求的请求头信息。

    3. Response headers(响应头 )

    • Access-Control-Allow-Origin:表示允许哪些原始域进行跨域访问。(字符数组)
    • Access-Control-Allow-Credentials:表示是否允许客户端获取用户凭据。(布尔类型)使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。 2.服务器端:设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。正确姿势如下:

    • Access-Control-Allow-Methods:表示跨域请求的方式的允许范围。(例如只授权GET/POST)
    • Access-Control-Allow-Headers:表示跨域请求的头部的允许范围。
    • Access-Control-Expose-Headers:表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息)
    • Access-Control-Max-Age:表示预检请求 [Preflight Request] 的最大缓存时间。

    二、CORS实现跨域访问

    授权方式

    • 方式1:返回新的CorsFilter
    • 方式2:重写WebMvcConfigurer
    • 方式3:使用注解(@CrossOrigin)
    • 方式4:手工设置响应头(HttpServletResponse )

    注:

    (1)CorsFilter / WebMvcConfigurer / @CrossOrigin 需要SpringMVC 4.2 以上的版本才支持,对应SpringBoot 1.3 版本以上都支持这些CORS特性。不过,使用SpringMVC4.2 以下版本的小伙伴也不用慌,直接使用方式4通过手工添加响应头来授权CORS跨域访问也是可以的。

    (2)方式1和方式2属于全局CORS配置,方式3和方式4属于局部CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过@CrossOrigin注解来进行细粒度更高的跨域资源控制。

    1. 返回新的CorsFilter(全局跨域)

    在任意配置类,返回一个新的CorsFilter Bean,并添加映射路径和具体的CORS配置信息。 

    package com.hehe.yyweb.config;
    
    @Configuration
    public class GlobalCorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            //1.添加CORS配置信息
            CorsConfiguration config = new CorsConfiguration();
              //放行哪些原始域
              config.addAllowedOrigin("*");
              //是否发送Cookie信息
              config.setAllowCredentials(true);
              //放行哪些原始域(请求方式)
              config.addAllowedMethod("*");
              //放行哪些原始域(头部信息)
              config.addAllowedHeader("*");
              //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
              config.addExposedHeader("*");
    
            //2.添加映射路径
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
    
            //3.返回新的CorsFilter.
            return new CorsFilter(configSource);
        }
    }

    2. 重写WebMvcConfigurer(全局跨域)

    在任意配置类,返回一个新的WebMvcConfigurer Bean,并重写其提供的跨域请求处理的接口,目的是添加映射路径和具体的CORS配置信息。 

    package com.hehe.yyweb.config;
    
    @Configuration
    public class GlobalCorsConfig {
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurer() {
                @Override
                //重写父类提供的跨域请求处理的接口
                public void addCorsMappings(CorsRegistry registry) {
                    //添加映射路径
                    registry.addMapping("/**")
                            //放行哪些原始域
                            .allowedOrigins("*")
                            //是否发送Cookie信息
                            .allowCredentials(true)
                            //放行哪些原始域请求方式,可以使用通配符*
                            .allowedMethods("GET","POST", "PUT", "DELETE")
                            //放行哪些原始域头部信息,可以使用通配符*
                            .allowedHeaders("*")
                            //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                            .exposedHeaders("Header1", "Header2")
                         //预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求,当预检请求通过后,浏览器会发送真实请求到服务器。这就实现了跨域请求
                            .maxAge(3600);
                }
            };
        }
    }

    3. 使用注解(局部跨域)

    在方法上(@RequestMapping)使用注解 @CrossOrigin :

    @RequestMapping("/hello")
    @ResponseBody
    @CrossOrigin("http://localhost:8080") 
    public String index( ){
        return "Hello World";
    }

    或者在控制器(@Controller)上使用注解 @CrossOrigin : 

    @Controller
    @CrossOrigin(origins = "http://xx-domain.com", maxAge = 3600)
    public class AccountController {
        @RequestMapping("/hello")
        @ResponseBody
        public String index( ){
            return "Hello World";
        }
    }

    4. 手工设置响应头(局部跨域 )

    使用HttpServletResponse对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里Origin的值也可以设置为”*” ,表示全部放行。

    @RequestMapping("/hello")
    @ResponseBody
    public String index(HttpServletResponse response){
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "Hello World";
    }

  • 相关阅读:
    A1066 Root of AVL Tree (25 分)
    A1099 Build A Binary Search Tree (30 分)
    A1043 Is It a Binary Search Tree (25 分) ——PA, 24/25, 先记录思路
    A1079; A1090; A1004:一般树遍历
    A1053 Path of Equal Weight (30 分)
    A1086 Tree Traversals Again (25 分)
    A1020 Tree Traversals (25 分)
    A1091 Acute Stroke (30 分)
    A1103 Integer Factorization (30 分)
    A1032 Sharing (25 分)
  • 原文地址:https://www.cnblogs.com/itfky/p/13737677.html
Copyright © 2011-2022 走看看