java WebTestClient -带Sping Boot 和Webflux的CORS

hpcdzsge  于 2023-03-28  发布在  Java
关注(0)|答案(6)|浏览(101)

我有Vuejs前端和一个Sping Boot Webflux控制器。现在浏览器在调用Spring Boot时抱怨CORS。
Access to XMLHttpRequest at 'https://...' from origin 'https://...' 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.
为了启用CORS,我尝试使用@CrossOrigin注解,如下所述:https://www.baeldung.com/spring-webflux-cors
但它没有帮助,不知何故,即使在控制器中使用@CrossOrigin注解,Spring也不会在响应中发送CORS头。
我还尝试了Bealdung教程中描述的WebTestClient,它确认头不存在:

java.lang.AssertionError: Response header 'Access-Control-Allow-Origin' expected:<[*]> but was:<null>

> OPTIONS /cors-enabled-endpoint
> WebTestClient-Request-Id: [1]
> Origin: [http://any-origin.com]
> Access-Control-Request-Method: [GET]

No content

< 500 INTERNAL_SERVER_ERROR Internal Server Error
< Vary: [Origin, Access-Control-Request-Method, Access-Control-Request-Headers]

0 bytes of content (unknown content-type).

如果我用response.expectHeader().exists("Access-Control-Allow-Origin");测试,我得到:

java.lang.AssertionError: Response header 'Access-Control-Allow-Origin' does not exist

任何想法为什么CORS配置中所描述的上述链接不工作?我也尝试启用CORS的全局配置和启用CORS与WebFilter.但似乎没有工作.

envsm3lx

envsm3lx1#

Thinice的解决方案是99.9%。Spring WebTestClient CORS测试要求URI包含 any 主机名和端口。WebTestClient忽略 * 实际 * 主机名和端口以连接到测试Web服务器:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class MyTestClass {

    @Autowired
    private WebTestClient webTestClient;
    
    @Test
    void corsTest() {
        webTestClient.get()
                .uri("http://hostname-ignored:666/cors-enabled-endpoint")
                .header("Origin", "http://any-origin.com")
                .exchange()   
                .expectHeader()
                  .valueEquals("Access-Control-Allow-Origin", "*");
    }    
}

此外,可以省略显式端口,它将继续工作:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class MyTestClass {

    @Autowired
    private WebTestClient webTestClient;
    
    @Test
    void corsTest() {
        webTestClient.get()
                .uri("http://look-ma-no-port/cors-enabled-endpoint")
                .header("Origin", "http://any-origin.com")
                .exchange()   
                .expectHeader()
                  .valueEquals("Access-Control-Allow-Origin", "*");
    }
}

要为所有端点启用CORS,可以使用给定的WebFluxConfigurer:

@Configuration(proxyBeanMethods = false)
public class MyWebFluxConfigurer {

  @Bean
  public WebFluxConfigurer corsConfigurer() {
    return new WebFluxConfigurerComposite() {

      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
      }
    };
  }
}
  • 包含Origin头是很重要的。如果没有Origin头,将无法设置Access-Control-Allow-Origin头,测试将失败。
  • 将Origin设置为与URI相同的主机名将被视为相同的源,因此不会设置跨源头。
  • RichArt建议包含spring-boot-starter-web依赖项,但这并不是启用CORS测试的特别要求。
  • 此答案仅适用于测试。它假设您已在服务器中启用CORS。
  • 我的答案是使用Spring WebFlux 5.3.10。
kzipqqlq

kzipqqlq2#

对我来说,在不添加spring-starter-web依赖的情况下,实际上是使用web过滤器,并在http方法为OPTIONS时强制返回。

@Configuration
public class CorsGlobalConfiguration implements WebFilter {

@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange,
                         WebFilterChain webFilterChain) {
    ServerHttpRequest request = serverWebExchange.getRequest();
    ServerHttpResponse response = serverWebExchange.getResponse();
    HttpHeaders headers = response.getHeaders();
    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
    headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
    headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "18000L");
    if (request.getMethod() == HttpMethod.OPTIONS) {
        response.setStatusCode(HttpStatus.OK);
        return Mono.empty();//HERE
    }
    return webFilterChain.filter(serverWebExchange);
}

}

Source

rqqzpn5f

rqqzpn5f3#

@RichArt的解决方案接近99%--但你不需要依赖(spring-boot-starter-web);由于它检查CORS,Spring似乎需要帮助了解您在测试中从哪个方案和主机中命中它;它不能派生'scheme'(http)或具有较短URI的主机。

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class MyTestClass {

    @Autowired
    private WebTestClient webTestClient;

    @LocalServerPort
    private Int lsp;

    @Test
    void corsTest() {
        ResponseSpec response = webTestClient.get()
                .uri("http://localhost" + lsp.toString() + "/cors-enabled-endpoint")
                .header("Origin", "http://any-origin.com")
                .exchange();

        response.expectHeader()
                .valueEquals("Access-Control-Allow-Origin", "*");
    }

}
kqhtkvqz

kqhtkvqz4#

@CrossOriginJavaDocs中提到
SpringWebMVC和SpringWebFlux都通过各自模块中的RequestMappingHandlerMapping来支持这个annotation。
这意味着您的CORS设置将添加到CorsConfiguration
如果您使用的是Spring Security,则需要启用CORS,以便使用CorsConfiguration。

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

从JavaDocs
添加要使用的CorsFilter。如果提供了名为corsFilter的bean,则使用该CorsFilter。否则,如果定义了corsConfigurationSource,则使用该CorsConfiguration。否则,如果Spring MVC在classpath上,则使用HandlerMappingIntrospector。
请注意,如果您发送的请求(cookie)的凭据,您需要将其添加到您的CORS设置

@CrossOrigin(allowCredentials = "true")
syqv5f0l

syqv5f0l5#

解决方案是为WebTestClient使用以下配置:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient

class MyTestClass {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    void corsTest() {
        ResponseSpec response = webTestClient.get()
                .uri("/cors-enabled-endpoint")
                .header("Origin", "http://any-origin.com")
                .exchange();

        response.expectHeader()
                .valueEquals("Access-Control-Allow-Origin", "*");
    }

}

我还需要添加spring-boot-starter-web依赖项,这非常奇怪,因为我只使用Webflux。但是没有它,IllegalArgumentException: Actual request scheme must not be null测试仍然失败。

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
</dependency>

现在,测试是绿色的!

jchrr9hc

jchrr9hc6#

我尝试了解决方案与任何主机,但我得到了

Failed to resolve 'hostname-ignored' after 4 queries ; nested exception is java.net.UnknownHostExceptio

相关问题