«1. Обзор

В предыдущем посте мы узнали о спецификации Cross-Origin Resource Sharing (CORS) и о том, как ее использовать в Spring.

В этом кратком руководстве мы настроим аналогичную конфигурацию CORS, используя платформу Spring 5 WebFlux.

Прежде всего, мы увидим, как мы можем включить этот механизм в API на основе аннотаций.

Затем мы проанализируем, как включить его для всего проекта в виде глобальной конфигурации или с помощью специального веб-фильтра.

2. Включение CORS для аннотированных элементов

Spring предоставляет аннотацию @CrossOrigin для включения запросов CORS к классам контроллера и/или методам обработчика.

2.1. Использование @CrossOrigin в методе обработчика запросов

Давайте добавим эту аннотацию к нашему сопоставленному методу запроса:

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

Мы будем использовать WebTestClient (как мы объясняли в разделе «4. Тестирование» этого поста) чтобы проанализировать ответ, который мы получаем от этой конечной точки:

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

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

Кроме того, мы можем попробовать предварительный запрос, чтобы убедиться, что конфигурация 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");

Аннотация @CrossOrigin имеет следующее конфигурация по умолчанию:

    Разрешает все источники (что объясняет значение «*» в заголовке ответа) Разрешает все заголовки Все HTTP-методы, отображаемые методом обработчика, разрешены Учетные данные не включены Значение «max-age» составляет 1800 секунд (30 минут)

Однако любое из этих значений можно переопределить с помощью параметров аннотации.

2.2. Использование @CrossOrigin в контроллере

Эта аннотация также поддерживается на уровне класса и влияет на все его методы.

В случае, если конфигурация на уровне класса не подходит для всех наших методов, мы можем аннотировать оба элемента, чтобы получить желаемый результат:

@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. Включение CORS в глобальной конфигурации

Мы также можем определить глобальную конфигурацию CORS, переопределив метод addCorsMappings() реализации WebFluxConfigurer.

Кроме того, реализации требуется аннотация @EnableWebFlux для импорта конфигурации Spring WebFlux в простое приложение Spring. Если мы используем 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);
    }
}

В результате мы разрешаем обработку запросов из разных источников для этого конкретного шаблона пути.

Конфигурация по умолчанию аналогична @CrossOrigin, но разрешены только методы GET, HEAD и POST.

Мы также можем комбинировать эту конфигурацию с локальной:

    Для атрибутов с несколькими значениями результирующая конфигурация CORS будет добавлением каждой спецификации. С другой стороны, локальные значения будут иметь приоритет над глобальными. для однозначных

Использование этого подхода неэффективно для функциональных конечных точек.

4. Включение CORS с помощью веб-фильтра

Лучший способ включить CORS на функциональных конечных точках — использовать веб-фильтр.

Как мы видели в этом посте, мы можем использовать веб-фильтры для изменения запросов и ответов, сохраняя при этом нетронутой реализацию конечной точки.

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);
}

Это также эффективно для аннотированных обработчиков, но его нельзя комбинировать с более точным @ Конфигурация CrossOrigin.

Мы должны помнить, что CorsConfiguration не имеет конфигурации по умолчанию.

Таким образом, если мы не укажем все соответствующие атрибуты, реализация CORS будет в значительной степени ограничивающей.

Простым способом установки значений по умолчанию является использование метода applyPermitDefaultValues() для объекта.

5. Заключение

В заключение, на очень коротких примерах мы узнали, как включить CORS в нашем сервисе на основе webflux.

Мы видели разные подходы, поэтому все, что нам нужно сделать сейчас, это проанализировать, какой из них лучше всего соответствует нашим требованиям.

Мы можем найти множество примеров в нашем репозитории GitHub, а также тестовые случаи, в которых мы анализируем большинство крайних случаев, касающихся этой темы.