注解@CrossOrigin解决跨域问题

本文围绕Spring注解@CrossOrigin展开,介绍跨域(CORS)支持,指出Spring Framework 4.2 GA开始支持。详细阐述使用方法,包括controller配置、全局配置、XML命名空间配置等,还说明了其工作原理和基于过滤器的支持。最后分析注解不起作用的原因并给出解决方案。

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

注解@CrossOrigin

  出于安全原因,浏览器禁止Ajax调用驻留在当前原点之外的资源。例如,当你在一个标签中检查你的银行账户时,你可以在另一个选项卡上拥有EVILL网站。来自EVILL的脚本不能够对你的银行API做出Ajax请求(从你的帐户中取出钱!)使用您的凭据。

  跨源资源共享(CORS)是由大多数浏览器实现的W3C规范,允许您灵活地指定什么样的跨域请求被授权,而不是使用一些不太安全和不太强大的策略,如IFRAME或JSONP。

 

一、跨域(CORS)支持:

  Spring Framework 4.2 GA为CORS提供了第一类支持,使您比通常的基于过滤器的解决方案更容易和更强大地配置它。所以springMVC的版本要在4.2或以上版本才支持@CrossOrigin

 

二、使用方法:

1、controller配置CORS

1.1、controller方法的CORS配置,您可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):

@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

其中@CrossOrigin中的2个参数:

origins  : 允许可访问的域列表

maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

1.2、为整个controller启用@CrossOrigin

复制代码

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

其中@CrossOrigin中的2个参数:

origins  : 允许可访问的域列表

maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

1.2、为整个controller启用@CrossOrigin

复制代码

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

其中@CrossOrigin中的2个参数:

origins  : 允许可访问的域列表

maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

1.2、为整个controller启用@CrossOrigin

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。

1.3、同时使用controller和方法级别的CORS配置,Spring将合并两个注释属性以创建合并的CORS配置。

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin(origins = "http://domain2.com")
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

1.4、如果您正在使用Spring Security,请确保在Spring安全级别启用CORS,并允许它利用Spring MVC级别定义的配置。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

2、全局CORS配置

  除了细粒度、基于注释的配置之外,您还可能需要定义一些全局CORS配置。这类似于使用筛选器,但可以声明为Spring MVC并结合细粒度@CrossOrigin配置。默认情况下,所有origins and GET, HEAD and POST methods是允许的。

JavaConfig

使整个应用程序的CORS简化为:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

如果您正在使用Spring Boot,建议将WebMvcConfigurer bean声明如下

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

您可以轻松地更改任何属性,以及仅将此CORS配置应用到特定的路径模式:

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
        .allowedOrigins("http://domain2.com")
        .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
        .exposedHeaders("header1", "header2")
        .allowCredentials(false).maxAge(3600);
}

如果您正在使用Spring Security,请确保在Spring安全级别启用CORS,并允许它利用Spring MVC级别定义的配置。

3、XML命名空间

还可以将CORS与MVC XML命名空间配置。

a、如果整个项目所有方法都可以访问,则可以这样配置;此最小XML配置使CORS在/**路径模式具有与JavaConfig相同的缺省属性:

<mvc:cors>
    <mvc:mapping path="/**" />
</mvc:cors>

其中* 表示匹配到下一层;** 表示后面不管有多少层,都能匹配。

如:

<mvc:cors>  
    <mvc:mapping path="/api/*"/>  
</mvc:cors> 

这个可以匹配到的路径有:

/api/aaa

/api/bbbb

不能匹配的:

/api/aaa/bbb

因为* 只能匹配到下一层路径,如果想后面不管多少层都可以匹配,配置如下:

<mvc:cors>  
    <mvc:mapping path="/api/**"/>  
</mvc:cors>  

注:其实就是一个(*)变成两个(**)

b、也可以用定制属性声明几个CORS映射:

<mvc:cors>

    <mvc:mapping path="/api/**"
        allowed-origins="http://domain1.com, http://domain2.com"
        allowed-methods="GET, PUT"
        allowed-headers="header1, header2, header3"
        exposed-headers="header1, header2" allow-credentials="false"
        max-age="123" />

    <mvc:mapping path="/resources/**"
        allowed-origins="http://domain1.com" />

</mvc:cors>

请求路径有/api/,方法示例如下:

@RequestMapping("/api/crossDomain")  
@ResponseBody  
public String crossDomain(HttpServletRequest req, HttpServletResponse res, String name){  
    ……  
    ……  
} 

c、如果使用Spring Security,不要忘记在Spring安全级别启用CORS

<http>
    <!-- Default to Spring MVC's CORS configuration -->
    <cors />
    ...
</http>

4、How does it work?

  CORS请求(包括预选的带有选项方法)被自动发送到注册的各种HandlerMapping 。它们处理CORS准备请求并拦截CORS简单和实际请求,这得益于CorsProcessor实现(默认情况下默认DefaultCorsProcessor处理器),以便添加相关的CORS响应头(如Access-Control-Allow-Origin)。 CorsConfiguration 允许您指定CORS请求应该如何处理:允许origins, headers, methods等。

a、AbstractHandlerMapping#setCorsConfiguration() 允许指定一个映射,其中有几个CorsConfiguration 映射在路径模式上,比如/api/**。

b、子类可以通过重写AbstractHandlerMapping类的getCorsConfiguration(Object, HttpServletRequest)方法来提供自己的CorsConfiguration。

c、处理程序可以实现 CorsConfigurationSource接口(如ResourceHttpRequestHandler),以便为每个请求提供一个CorsConfiguration

5、基于过滤器的CORS支持

  作为上述其他方法的替代,Spring框架还提供了CorsFilter。在这种情况下,不用使用@CrossOrigin或WebMvcConfigurer#addCorsMappings(CorsRegistry),,例如,可以在Spring Boot应用程序中声明如下的过滤器:

@Configuration
public class MyConfiguration {

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://domain1.com");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

三、spring注解@CrossOrigin不起作用的原因

1、是springMVC的版本要在4.2或以上版本才支持@CrossOrigin

2、非@CrossOrigin没有解决跨域请求问题,而是不正确的请求导致无法得到预期的响应,导致浏览器端提示跨域问题。

3、在Controller注解上方添加@CrossOrigin注解后,仍然出现跨域问题,解决方案之一就是:

在@RequestMapping注解中没有指定Get、Post方式,具体指定后,问题解决。

类似代码如下:

@CrossOrigin
@RestController
public class person{
    
    @RequestMapping(method = RequestMethod.GET)
    public String add() {
        // 若干代码
    }
}

四、参考文章:

1、官方文档https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

2、http://fanshuyao.iteye.com/blog/2384189

2、https://blog.youkuaiyun.com/taiyangnimeide/article/details/78305131

3、https://blog.youkuaiyun.com/snowin1994/article/details/53035433

<think>好的,我现在需要解决用户在使用@CrossOrigin注解后无法调用getMD5String方法的问题。首先,我得理清楚问题可能的原因。 用户提到在配置了后,某个具体的方法失效了。这说明配置可能影响到了该方法。首先,我应该检查@CrossOrigin的用法是否正确。这个注解可以用在类或方法上,如果类上已经配置了,方法上的配置可能会有冲突。比如,如果类上的注解覆盖了某些设置,可能导致方法级别的配置失效。 然后,考虑配置是否影响到了其他拦截器或过滤器。例如,Shiro或Spring Security的权限验证可能会因为配置而拦截请求。用户之前提到过Shiro的问题,比如没有认证导致错误,所以需要检查是否有权限相关的拦截器阻止了方法的调用。可能需要在Shiro的配置中放行相关路径,或者在Spring Security中配置设置,而不是仅仅依赖@CrossOrigin。 另外,浏览器的CORS预检请求(OPTIONS)是否被正确处理?如果后端没有处理OPTIONS请求,可能导致真正的请求(如POST或GET)无法到达方法。需要确认服务器是否对OPTIONS请求返回了正确的响应头,允许访问。 还有可能是方法本身的路径或请求方式不匹配。比如,@CrossOrigin配置的origins、methods或allowedHeaders与实际请求不符,导致预检失败,从而无法调用方法。需要检查注解中的属性是否与前端请求一致。 另外,日志信息也很重要。用户提到整合了Log4J,可能需要查看日志输出,确认是否有异常或错误信息,比如权限拒绝或方法找不到。如果getMD5String方法需要特定的参数或请求体,可能因为配置导致参数解析失败,比如多RequestBody的问题,参考用户提到的引用[1],可能需要自定义参数解析器。 最后,可能需要全局配置,而不是使用注解。比如,通过WebMvcConfigurer来配置全局设置,避免注解被其他配置覆盖。同时,确保Spring Boot的版本兼容,某些版本可能存在处理的bug,需要升级或调整配置。 总结可能的原因:注解配置冲突、权限拦截器拦截、预检请求处理不当、参数不匹配、参数解析问题等。解决方案应逐步排查这些可能性,调整配置,查看日志,确保所有环节都允许访问。</think>### 问题分析:使用@CrossOrigin注解后无法调用getMD5String方法 #### 1. **检查@CrossOrigin注解配置** - **作用范围**:确认注解是否直接标注在`getMD5String`方法或所在控制器类上。例如: ```java @RestController @CrossOrigin(origins = "*", allowedHeaders = "*") // 类级别配置 public class YourController { @GetMapping("/md5") @CrossOrigin // 方法级别配置(若需要覆盖类级别配置) public String getMD5String() { // ... } } ``` - **属性匹配**:检查`origins`、`methods`、`allowedHeaders`是否与前端请求匹配。例如前端使用`POST`但注解仅允许`GET`会导致失败。 #### 2. **权限框架拦截(如Shiro)** - **路径放行**:若使用Shiro,可能拦截了请求。在Shiro配置中放行`/md5`路径: ```java @Bean public ShiroFilterChainDefinition shiroFilter() { DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition(); chain.addPathDefinition("/md5", "anon"); // 匿名访问 return chain; } ``` - **认证状态检查**:确保请求中携带了必要的Token或Session信息(参考引用[^2]中提到的Shiro认证问题)。 #### 3. **预检请求(OPTIONS)处理** - **自动处理**:Spring Boot默认会处理OPTIONS请求,但若自定义了拦截器(如登录拦截器),需手动放行OPTIONS请求: ```java public class YourInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpStatus.OK.value()); return false; } return true; } } ``` #### 4. **全局配置覆盖** - **替代注解方案**:使用`WebMvcConfigurer`全局配置,避免注解冲突: ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*"); } } ``` #### 5. **参数解析问题** - **多RequestBody冲突**:若`getMD5String`方法需要多个`@RequestBody`参数,需实现自定义解析器(参考引用[^1]): ```java public class MultiRequestBodyResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } @Override public Object resolveArgument(/* 参数解析逻辑 */) { // 自定义解析逻辑 } } ``` #### 6. **日志排查** - **启用详细日志**:通过Log4J输出详细调试信息(参考引用[^3]): ```xml <!-- log4j2.xml --> <Configuration> <Loggers> <Logger name="org.springframework.web" level="debug"/> </Loggers> </Configuration> ``` - **检查异常堆栈**:查看是否有`Access-Control-Allow-Origin`缺失、`405 Method Not Allowed`或权限拒绝日志。 --- ### 最终解决方案步骤 1. **优先使用全局配置**,禁用`@CrossOrigin`注解测试是否恢复。 2. **检查Shiro/Security放行规则**,确保路径未被拦截。 3. **捕获请求日志**,确认请求头、方法类型与后端配置一致。 4. **升级Spring Boot版本**(若版本低于2.4.x,存在相关兼容性问题)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值