Spring Webflux and CORS – Spring Webflux和CORS

最后修改: 2018年 7月 21日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In a previous post, we learned about Cross-Origin Resource Sharing (CORS) specification and how to use it within Spring.

前一篇文章中,我们了解了跨源资源共享(CORS)规范以及如何在Spring中使用它。

In this quick tutorial, we’ll set up a similar CORS configuration using Spring’s 5 WebFlux framework.

在这个快速教程中,我们将使用Spring的5个WebFlux框架设置一个类似的CORS配置。

First of all, we’ll see how we can enable the mechanism on annotation-based APIs.

首先,我们将看到如何在基于注释的API上启用该机制。

Then, we’ll analyze how to enable it on the whole project as a global configuration, or by using a special WebFilter.

然后,我们将分析如何在整个项目中以全局配置的方式启用它,或通过使用一个特殊的WebFilter

2. Enabling CORS on Annotated Elements

2.在注释的元素上启用CORS

Spring provides the @CrossOrigin annotation to enable CORS requests on controller classes and/or handler methods.

Spring提供了@CrossOrigin注解,以便在控制器类和/或处理方法上启用CORS请求。

2.1. Using @CrossOrigin on a Request Handler Method

2.1.在一个请求处理方法上使用@CrossOrigin

Let’s add this annotation to our mapped request method:

让我们把这个注解添加到我们映射的请求方法中。

@CrossOrigin
@PutMapping("/cors-enabled-endpoint")
public Mono<String> corsEnabledEndpoint() {
    // ...
}

We’ll use a WebTestClient (as we explained in section ‘4. Testing’ of this post) to analyze the response we get from this endpoint :

我们将使用一个WebTestClient(正如我们在这篇文章的’4.测试’的这个帖子)来分析我们从这个端点得到的响应。

ResponseSpec response = webTestClient.put()
  .uri("/cors-enabled-endpoint")
  .header("Origin", "http://any-origin.com")
  .exchange();

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

In addition, we can try out a preflight request to make sure the CORS configuration is working as expected:

此外,我们可以尝试一个预检请求,以确保CORS配置按预期工作。

ResponseSpec response = webTestClient.options()
  .uri("/cors-enabled-endpoint")
  .header("Origin", "http://any-origin.com")
  .header("Access-Control-Request-Method", "PUT")
  .exchange();

response.expectHeader()
  .valueEquals("Access-Control-Allow-Origin", "*");
response.expectHeader()
  .valueEquals("Access-Control-Allow-Methods", "PUT");
response.expectHeader()
  .exists("Access-Control-Max-Age");

The @CrossOrigin annotation has the following default configuration:

@CrossOrigin注解有以下默认配置。

  • Allows all origins (that explains the ‘*’ value in the response header)
  • Allows all headers
  • All HTTP methods mapped by the handler method are allowed
  • Credentials are not enabled
  • The ‘max-age’ value is of 1800 seconds (30 minutes)

However, any of these values can be overridden using the annotation’s parameters.

然而,这些值中的任何一个都可以用注解的参数来覆盖。

2.2. Using @CrossOrigin on the Controller

2.2.在控制器上使用@CrossOrigin

This annotation is also supported at a class level, and it will affect all its methods.

在类的层面上也支持这个注解,它将影响其所有方法。

In case the class-level configuration isn’t suitable for all our methods, we can annotate both elements to get the desired result:

如果类级配置不适合我们所有的方法,我们可以对这两个元素进行注解,以获得理想的结果。

@CrossOrigin(value = { "http://allowed-origin.com" },
  allowedHeaders = { "Baeldung-Allowed" },
  maxAge = 900
)
@RestController
public class CorsOnClassController {

    @PutMapping("/cors-enabled-endpoint")
    public Mono<String> corsEnabledEndpoint() {
        // ...
    }

    @CrossOrigin({ "http://another-allowed-origin.com" })
    @PutMapping("/endpoint-with-extra-origin-allowed")
    public Mono<String> corsEnabledWithExtraAllowedOrigin() {
        // ...
    }

    // ...
}

3. Enabling CORS on the Global Configuration

3.在全局配置中启用 CORS

We can also define a global CORS configuration by overriding the addCorsMappings() method of a WebFluxConfigurer implementation.

我们还可以通过覆盖addCorsMappings()方法来定义全局CORS配置,WebFluxConfigurer实现。

In addition, the implementation needs the @EnableWebFlux annotation to import the Spring WebFlux configuration in a plain Spring application. If we’re using Spring Boot, then we only need this annotation if we want to override the auto-configuration:

此外,该实现还需要@EnableWebFlux注解,以便在普通Spring应用程序中导入Spring WebFlux配置。如果我们使用的是Spring Boot,那么只有在我们想覆盖自动配置的时候才需要这个注解。

@Configuration
@EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
          .allowedOrigins("http://allowed-origin.com")
          .allowedMethods("PUT")
          .maxAge(3600);
    }
}

As a result, we are enabling cross-origin request handling for that particular path pattern.

因此,我们正在为该特定路径模式启用跨源请求处理。

The default configuration is similar to the @CrossOrigin one, but with only the GET, HEAD, and POST methods allowed.

默认配置与@CrossOrigin类似,但只允许使用GET, HEAD, 和POST方法。

We can also combine this configuration with a local one:

我们还可以将这种配置与本地配置结合起来。

  • For the multiple-value attributes, the resulting CORS configuration will be the addition of each specification
  • On the other hand, the local values will have precedence over the global ones for the single-value ones

Using this approach is not effective for functional endpoints, though.

不过,使用这种方法对功能端点并不有效。

4. Enabling CORS with a WebFilter

4.用WebFilter启用CORS

The best way to enable CORS on functional endpoints is by using a WebFilter.

在功能端点上启用CORS的最佳方式是使用WebFilter

As we’ve seen in this post, we can use WebFilters to modify requests and responses, while keeping the endpoint’s implementation intact.

正如我们所看到的在这篇文章中,我们可以使用WebFilters来修改请求和响应,同时保持端点的实现不变。

Spring provides the built-in CorsWebFilter so as to deal with the cross-origin configurations easily:

Spring提供了内置的CorsWebFilter,以便轻松处理跨源配置:

@Bean
CorsWebFilter corsWebFilter() {
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowedOrigins(Arrays.asList("http://allowed-origin.com"));
    corsConfig.setMaxAge(8000L);
    corsConfig.addAllowedMethod("PUT");
    corsConfig.addAllowedHeader("Baeldung-Allowed");

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

    return new CorsWebFilter(source);
}

This is also effective for annotated handlers, but it can’t be combined with a more fine-grained @CrossOrigin configuration.

这对有注释的处理程序也很有效,但它不能与更精细的@CrossOrigin配置相结合。

We have to keep in mind that the CorsConfiguration doesn’t have a default configuration.

我们必须记住,CorsConfiguration没有一个默认配置。

Thus, unless we specify all the relevant attributes, the CORS implementation will be pretty much restrictive.

因此,除非我们指定所有相关的属性,否则CORS的实现将是相当大的限制。

A simple way of setting the default values is by using the applyPermitDefaultValues() method on the object.

设置默认值的一个简单方法是使用对象上的applyPermitDefaultValues()方法。

5. Conclusion

5.总结

In conclusion, we learned with very short examples of how to enable CORS on our webflux-based service.

最后,我们用很短的例子了解了如何在我们基于webflux的服务上启用CORS。

We saw different approaches, therefore all we have to do now is analyze which one suits our requirements best.

我们看到了不同的方法,因此我们现在要做的就是分析哪种方法最适合我们的要求。

We can find plenty of examples in our GitHub repo, together with test cases where we analyze most of the edge cases regarding this topic.

我们可以在我们的GitHub repo中找到大量的例子,同时还有测试案例,我们在其中分析了关于这个主题的大多数边缘案例。