Java Spring 引导 Webflux cors 被阻止

Java Spring Boot Webflux cors blocked

我正在尝试使用 Webflux 构建一个 Angular 和 Spring 启动应用程序,而不是一开始就陷入实体和数据库的完整 CRUD 教程中,我认为我会首先看看我是否可以让客户端显示服务器返回的字符串,正如 spring 引导文档所教导的那样 here。为此,我有以下代码:

//Angular client
  private currencyGreetingUrl: string;

  constructor(private http: HttpClient) {
    this.currencyGreetingUrl = 'http://localhost:8080/currency';
  }

  public getCurrencyGreeting(): Observable<string> {
    return this.http.get<string>(this.currencyGreetingUrl);
  }

//Spring Boot Web Client
@CrossOrigin(origins = "http://localhost:4200")
public class CurrencyWebClient {
  private WebClient client = WebClient.create("http://localhost:8080");

  private Mono<ClientResponse> result = client.get()
      .uri("/currency")
      .accept(MediaType.TEXT_PLAIN)
      .exchange();
  
  public String getResult() {
    return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
  }
}

//Spring boot handler
@Component
public class CurrencyHandler {

  public Mono<ServerResponse> currency(ServerRequest request) {
    return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
      .body(BodyInserters.fromValue("Hello, Currency On The Go!"));
  }
}

//Spring Boot router

@Configuration
public class CurrencyRouter {

  @Bean
  public RouterFunction<ServerResponse> route(CurrencyHandler currencyHandler) {

    return RouterFunctions
      .route(RequestPredicates.GET("/currency").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), currencyHandler::currency);
  }
}

但是,当 运行 客户端和服务器 Access to XMLHttpRequest at 'http://localhost:8080/currency' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

时出现此错误

我是 Spring Boot 的新手,一直在四处寻找建议,但我通常找到的解决方案涉及配置、控制器 类 以及其他比我更构建的工件目前有。我怎样才能让它工作?感谢您的帮助。

你配置好cors了吗? 如果没有,请尝试以下操作:

请同时阅读第二个答案,因为发布的答案漏掉了一行。

为了我在将 Webflux 与基于浏览器的前端一起使用时需要快速测试的目的,我使用支持 CORS 的 Chrome 扩展来快速测试。这显然不适合生产。

如果您处于纯微服务/后端通信的情况下,您可能只需要遵循 Spring 的预期工作流程。根据我的经验,Spring Webflux 有一些强大的结果,但设置很挑剔。不幸的是,您提到但正在避免的那些配置 类,或者 Kotlin 的注释或基于 DSL 的解决方案目前是预期的方式。根据我的经验,它们确实有效,一旦你设置好它们,就可以为其他微服务制作一个快速 github 就绪模板(当时我正在使用 Spring 和 Kotlin 构建微服务)。

编辑:我还要补充一点,您避免的那些配置和 类 是值得您花时间的,即使您花一个上午的时间在这些上面也会为提高生产力铺平道路。 Webflux 很棒(我已经将它与 Kotlin 和 Java 一起使用)但是当您跳转到异步/反应式 webflux 领域时,存在一些不可避免的陷阱和配置差异。当您意识到自己做对了事情时,配置中的乐趣就来了,当您可以推送如此多的请求时,您的数据库驱动程序吓坏了:) :) :)

您已决定使用 functional endpoints 而您没有使用 spring 我可以从您的标签中看出的安全性,这意味着此处提供的所有其他答案都是错误的。

使用函数式端点时,您必须意识到您已选择不使用基于 类 的传统注解。这意味着您失去了 spring 框架

提供的许多免费功能

功能端点更“低级”。因此,负责处理 CORS 的开发人员将落在您身上。

如果您是 Spring 和 webflux 的初学者,我不会选择这条路线。

The documentation states in the CORS chapter in the official webflux documentation:

You can apply CORS support through the built-in CorsWebFilter, which is a good fit with functional endpoints.

他们甚至提供了标准 CORS 过滤器的实现,您可以根据自己的需要进行自定义。

@Bean
CorsWebFilter corsFilter() {

    CorsConfiguration config = new CorsConfiguration();

    // Possibly...
    // config.applyPermitDefaultValues()

    config.setAllowCredentials(true);
    config.addAllowedOrigin("https://domain1.com");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);

    return new CorsWebFilter(source);
}

互联网上有数百个解释 CORS 的网页,这是 spring-boot、spring-security 标签中最常见的问题。我建议您阅读 CORS(您应该在此处提问之前完成)。

强烈建议您从这里开始阅读:

Mozilla CORS

确实我确实需要使用CorsWebFilter。然而,在阅读了一些 Spring Boot 及其依赖注入系统,并查看 Spring Boot 项目中不使用功能端点的不同切线相关的 cors 实现之后,我发现我必须放置我的应用程序根目录下的 ``CorsWebFilter``` 如下所示:

@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
        CurrencyWebClient client = new CurrencyWebClient();

        System.out.println(client.getResult());
    }

    @Bean
    CorsWebFilter corsFilter() {

        CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:4200");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

当然,这不是唯一的方法。但它解决了我最初遇到的这个小问题。谢谢大家