Java Spring Global CORS 配置不起作用,但控制器级别的配置起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37980914/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:52:31  来源:igfitidea点击:

Spring Global CORS configuration not working but Controller level config does

javaspring-mvchttp-headerscorscross-domain

提问by Adam James

I am trying to configure CORS globally via WebMvcConfigurerAdaptershown below. To test I am hitting my API endpoint via a small node app I created to emulate an external service. When I try this approach the response does not contain the correct headers and fails with

我正在尝试通过WebMvcConfigurerAdapter如下所示全局配置 CORS 。为了测试,我通过我创建的一个模拟外部服务的小节点应用程序访问我的 API 端点。当我尝试这种方法时,响应不包含正确的标头并且失败

XMLHttpRequest cannot load http://localhost:8080/api/query/1121. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:333' is therefore not allowed access.

Global Config

全局配置

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/api/query/**")
                    .allowedOrigins("*")
                    .allowedHeaders("*")
                    .allowCredentials(true);
        }
}

However when I utilize the @CrossOriginannotation like so it works just fine responding with the proper headers.

但是,当我@CrossOrigin像这样使用注释时,它可以很好地响应正确的标题。

@CrossOrigin(origins = "*", allowCredentials = "true", allowedHeaders = "*")
@RestController
@RequestMapping(value = "/api/query", produces = MediaType.APPLICATION_JSON_VALUE)
public class QueryController {
   ......
}

Produces

生产

Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:333

What am I missing to make the global config work (followed instructions here https://spring.io/blog/2015/06/08/cors-support-in-spring-framework). I feel like I'm missing something simple since annotating the controller works just fine.

我缺少什么才能使全局配置工作(按照此处的说明进行操作https://spring.io/blog/2015/06/08/cors-support-in-spring-framework)。我觉得我错过了一些简单的东西,因为注释控制器工作得很好。

回答by Brian Clozel

I think your mapping definition is missing a *:

我认为您的映射定义缺少一个*

registry.addMapping("/api/query/**")

Without that extra *, this configuration is not mapped to the /api/query/1121request path (but it would work on /api/query/5).

没有那个额外的*,这个配置不会映射到/api/query/1121请求路径(但它可以工作/api/query/5)。

回答by dhyanandra singh

you didn't declared method in it which is by default accept only get method. try registry.allowedMethods("*");

您没有在其中声明方法,默认情况下仅接受 get 方法。尝试registry.allowedMethods("*");

回答by outdev

In order for the global CORS config to work, the client must add these two headers in the OPTIONS request.

为了使全局 CORS 配置工作,客户端必须在 OPTIONS 请求中添加这两个标头。

Origin: http://host.com
Access-Control-Request-Method: POST

However the @CrossOrigin annotation requires just the "Origin" header.
Your client probably adds the "Origin" header but is missing the "Access-Control-Request-Method".....thats why it works for you with the @CrossOrigin, but doesn't with the global config.

但是,@CrossOrigin 注释只需要“Origin”标头。
您的客户端可能添加了“Origin”标头,但缺少“Access-Control-Request-Method”.....这就是为什么它适用于@CrossOrigin,但不适用于全局配置。

回答by Bharat Singh

I faced similar issue. I changed the WebMvcConfigurerAdapter to WebMvcConfigurationSupport and it started working.

我遇到了类似的问题。我将 WebMvcConfigurerAdapter 更改为 WebMvcConfigurationSupport 并开始工作。

In addition to this I also moved the RequestMappingHandlerMapping defined in xml configuration file to java configuration.

除此之外我还将xml配置文件中定义的RequestMappingHandlerMapping移到java配置中。

回答by Bharat Singh

I was able to get the Spring Global CORS configuration to work, after experiencing the exact problem documented in this issue. I had to do 2 things:

在遇到此问题中记录的确切问题后,我能够使 Spring Global CORS 配置工作。我必须做两件事:

  1. allowedOrigins cannot be * if allowCredentials is true. This is documented at Mozilla.org

  2. Remove mvc:annotation-driven from the spring XML. Cannot have BOTH the XML config and @EnableWebMvc. The global class won't work without @EnableWebMvc, thus mvc:annotation-driven must be removed.

  1. 如果 allowCredentials 为真,则 allowedOrigins 不能为 *。这记录在 Mozilla.org

  2. 从 spring XML 中删除 mvc:annotation-driven。不能同时拥有 XML 配置和 @EnableWebMvc。如果没有@EnableWebMvc,全局类将无法工作,因此必须删除 mvc:annotation-driven。

回答by Tomasz Poradowski

I had a similar issue and none of methods seemed to work (except using @CrossOriginannotation for each controller). I followed Bharat Singh'ssolution above and after some debugging of Spring Framework internals - here's what worked for me (Spring Boot 2.0.6 + Spring Framework 5.0.10):

我有一个类似的问题,似乎没有任何方法有效(除了@CrossOrigin为每个控制器使用注释)。我遵循了上面Bharat Singh 的解决方案,并在对 Spring Framework 内部进行了一些调试之后 - 这对我有用Spring Boot 2.0.6 + Spring Framework 5.0.10):

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

/* (non-Javadoc)
 * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
 */
@Override
protected void addCorsMappings(CorsRegistry registry) {
    //NOTE: servlet context set in "application.properties" is "/api" and request like "/api/session/login" resolves here to "/session/login"!
    registry.addMapping("/**")
        .allowedMethods("GET", "POST", "PUT", "DELETE")
        .allowedOrigins("*")
        .allowedHeaders("*")
        .allowCredentials(false);
    }
}

Initially when I used "/api/**"mapping it was configured within Spring, but since the application was deployed with "/api"context - requests like "/api/session/login"were internally mapped to "/session/login"and such mapping in CORS configuration was not found - please pay attention to that!

最初,当我使用"/api/**"映射时,它是在 Spring 中配置的,但是由于应用程序是使用"/api"上下文部署的- 请求"/api/session/login"在内部映射到"/session/login"并且在 CORS 配置中找不到这样的映射 - 请注意!

回答by Tom

I've just been having the exact same issue, with none of the solutions in this thread working. I've managed to solve it with the following:

我刚刚遇到了完全相同的问题,该线程中的任何解决方案都不起作用。我设法通过以下方法解决了它:

A new configuration bean:

一个新的配置 bean:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilterConfiguration {

  @Bean
  public CorsFilter corsFilter() {
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      CorsConfiguration config = new CorsConfiguration();
      config.setAllowCredentials(true);
      config.addAllowedOrigin("*");
      config.setAllowedMethods(Arrays.asList("POST", "OPTIONS", "GET", "DELETE", "PUT"));
      config.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization"));
      source.registerCorsConfiguration("/**", config);
      return new CorsFilter(source);
  }
}

A modification to my web.xml to add a new filter for all URLs:

修改我的 web.xml 为所有 URL 添加一个新过滤器:

<filter>
  <filter-name>corsFilter</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>corsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Obviously you can modify the cors config accordingly.

显然,您可以相应地修改 cors 配置。

回答by Jorge L. Morla

I was facing the same issue and after setting the maxAgeattribute everything started working ok!

我遇到了同样的问题,在设置maxAge属性后,一切都开始正常了!

@Bean
public WebMvcConfigurer CORSConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("*")
                    .allowedHeaders("*")
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD")
                    .maxAge(-1)   // add maxAge
                    .allowCredentials(false);
        }
    };
}

if you check the CrossOriginannotation it has a default value assigned to that attribute

如果您检查CrossOrigin注释,它会为该属性分配一个默认值

/**
 * <p>By default this is set to {@code 1800} seconds (30 minutes).
 */
long maxAge() default -1;

回答by Gustavo Bartolomeo

I have had the same problem working on a Spring mvc application (not Spring Boot). The only way I could solve the problem was to explicitly add a cors filter to the spring security filter chain:

我在处理 Spring mvc 应用程序(不是 Spring Boot)时遇到了同样的问题。我能解决这个问题的唯一方法是在 spring 安全过滤器链中显式地添加一个 cors 过滤器:

public class MySecurityInitializer extends AbstractSecurityWebApplicationInitializer {

  protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
    final FilterRegistration.Dynamic corsFilter = servletContext.addFilter("corsFilter", corsFilter());
    corsFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
  }

  protected CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(Arrays.asList(CrossOrigin.DEFAULT_ORIGINS));
    config.setAllowedMethods(Arrays.asList("POST", "OPTIONS", "GET", "DELETE", "PUT"));
    config.setAllowedHeaders(Arrays.asList(CrossOrigin.DEFAULT_ALLOWED_HEADERS));
    config.setAllowCredentials(CrossOrigin.DEFAULT_ALLOW_CREDENTIALS);
    config.setMaxAge(CrossOrigin.DEFAULT_MAX_AGE);
    source.registerCorsConfiguration("/**", config);

    return new CorsFilter(source);
  }

}

Luck!

运气!