Spring 里多种 CORS 配置方式

本文详细介绍了Spring中处理CORS(跨域资源共享)的多种方式,包括@CrossOrigin注解、WebMvcConfigurer配置类、自定义OriginFilter和CorsFilter。还特别讨论了在引入Spring Security后如何正确配置CORS,以及Filter与Interceptor的区别。文章通过实例展示了每种配置方式的工作原理和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:https://cloud.tencent.com/developer/article/1703212
https://cloud.tencent.com/developer/article/1513473

一、CORS 介绍

CORS全称是Cross-Origin Resource Sharing,直译过来就是跨域资源共享。

  • 从站点 A 请求站点 B 的资源的时候,由于浏览器的同源策略的影响,这样的跨域请求将被禁止发送;为了让跨域请求能够正常发送,我们需要一套机制在不破坏同源策略的安全性的情况下、允许跨域请求正常发送,这样的机制就是CORS
  • 要理解域、资源和同源策略这三个概念
    :指的是一个站点,由protocal、host和port三部分组成,其中host可以是域名,也可以是ip;port如果没有指明,则是使用protocal的默认端口
    资源:是指一个URL对应的内容,可以是一张图片、一种字体、一段HTML代码、一份JSON数据等等任何形式的任何内容
    同源策略:指的是为了防止XSS,浏览器、客户端应该仅请求与当前页面来自同一个域的资源,请求其他域的资源需要通过验证。
  • 当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域

二、预检请求——OPTIONS

跨域请求流程:
1.访问另一个域的资源
2.有可能会发起一次预检请求(非简单请求,或超过了Max-Age)
3.发起实际请求

  • 在CORS中,定义了一种预检请求,即preflight request,当实际请求不是一个简单请求时,会发起一次预检请求。预检请求是针对实际请求的 URL 发起一次OPTIONS请求,并带上下面三个headers:
    Origin:值为当前页面所在的域,用于告诉服务器当前请求的域。如果没有这个header,服务器将不会进行CORS验证。
    Access-Control-Request-Method:值为实际请求将会使用的方法
    Access-Control-Request-Headers:值为实际请求将会使用的header集合
  • 如果服务器端CORS验证失败,则会返回客户端错误,即4xx的状态码。
  • 否则,将会请求成功,返回200的状态码,并带上下面这些headers:
    Access-Control-Allow-Origin:允许请求的域,多数情况下,就是预检请求中的Origin的值
    Access-Control-Allow-Credentials:一个布尔值,表示服务器是否允许使用cookies
    Access-Control-Expose-Headers:实际请求中可以出现在响应中的headers集合
    Access-Control-Max-Age:预检请求返回的规则可以被缓存的最长时间,超过这个时间,需要再次发起预检请求
    Access-Control-Allow-Methods:实际请求中可以使用到的方法集合
  • 浏览器会根据预检请求的响应,来决定是否发起实际请求。

三、CORS 配置的方式

Spring 提供了多种配置CORS的方式,有的方式针对单个 API,有的方式可以针对整个应用;有的方式在一些情况下是等效的,而在另一些情况下却又出现不同。
在仅仅引入Spring Web的情况下,实现3.2 3.4这两种方式它们的区别会在引入Spring Security之后会展现出来

  • 假设我们有一个 API:
    @RestController
    class HelloController {
        @GetMapping("hello")
        fun hello(): String {
            return "Hello, CORS!"
        }
    }
    

3.1 @CrossOrigin注解

用@CorssOrigin注解需要引入Spring Web的依赖,该注解可以作用于方法或者类,可以针对这个方法或类对应的一个或多个 API 配置CORS规则:

@RestController
class HelloController {
    @GetMapping("hello")
    @CrossOrigin(origins = "http://localhost:63342", methods = {GET, POST, PUT, DELETE}, maxAge = 60L)//可以指定地址 方法 缓存时间
  	public String hello(String string ) {
        return "Hello, CORS!"
    }
}

3.2 WebMvcConfigurer 配置类

MvcConfigurer是一个接口,它同样来自于Spring Web。我们可以通过实现它的addCorsMappings方法来针对全局 API 配置CORS规则:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        /**
         * addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
         * allowedOrigins:允许访问的url,可以固定单条或者多条内容,如:"http://www.baidu.com"。
         * allowedMethods:允许的请求方式,如:POST、GET、PUT、DELETE等。
         * allowCredentials 是否发送cookie
         * maxAge:配置预检请求的有效时间
         * allowedHeaders:允许的请求header,可以自定义设置任意请求头信息。
         */
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");
    }
}

3.3 自定义OriginFilter 实现Filter过滤器

OriginFilter 通过实现Filter类 完成全局跨域配置(Spring MVC 4.2之前没提供对cors的支持 老项目会自定义过滤器)

@Configuration
public class OriginFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
        HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() { }

}

3.4 CorsFilter

CorsFilter同样来自于Spring Web,但是实现WebMvcConfigurer.addCorsMappings方法并不会使用到这个类,我们可以通过注入一个CorsFilter来使用它:(Spring MVC 4.2后内置了一个CorsFilter专门用于处理CORS请求问题)

@Configuration
public class CORSConfiguration {
    
    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8080");
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/hello",corsConfiguration);//添加地址
        return corsFilter();

    }
}

四、Spring Security 中的配置

在引入了Spring Security之后,我们会发现前面的方法都不能正确的配置CORS,每次preflight request都会得到一个401的状态码,表示请求没有被授权。这时,我们需要增加一点配置才能让CORS正常工作:

@Bean
   public CorsConfigurationSource CorsConfigurationSource (){
       CorsConfiguration corsConfiguration = new CorsConfiguration();
       corsConfiguration.addAllowedOrigin("http://localhost:8080");
       UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
       urlBasedCorsConfigurationSource.registerCorsConfiguration("/hello",corsConfiguration);
       return CorsConfigurationSource();
   }

五、Filter 与 Interceptor

在这里插入图片描述

  • 上图很形象的说明了Filter与Interceptor的区别,一个作用在DispatcherServlet调用前,一个作用在调用后。
    但实际上,它们本身并没有任何关系,是完全独立的概念。

  • Filter由Servlet标准定义,要求Filter需要在Servlet被调用之前调用,作用顾名思义,就是用来过滤请求。在Spring Web应用中,DispatcherServlet就是唯一的Servlet实现。

  • Interceptor由 Spring 自己定义,由DispatcherServlet调用,可以定义在Handler调用前后的行为。这里的Handler,在多数情况下,就是我们的Controller中对应的方法。

六、小结

  • 3.2配置 实现WebMvcConfigurer.addCorsMappings方法来进行的CORS配置,最后会在 Spring 的Interceptor或Handler 中生效
  • 3.4配置 注入CorsFilter的方式会让CORS验证在Filter中生效
  • 引入Spring Security后,需要调用HttpSecurity.cors方法以保证CorsFilter会在身份验证相关的Filter之前执行
    HttpSecurity.cors+WebMvcConfigurer.addCorsMappings是一种相对低效的方式,会导致跨域请求分别在Filter和Interceptor层各经历一次CORS验证
    HttpSecurity.cors+ 注册CorsFilter与HttpSecurity.cors+ 注册CorsConfigurationSource在运行的时候是等效的
  • 在 Spring 中,没有通过CORS验证的请求会得到状态码为 403 的响应
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值