Перейти к основному содержимому

Spring Webflux и CORS

· 4 мин. чтения

Упражнение: Сложение двух чисел

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

ANDROMEDA

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 = { "ForEach-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 с помощью WebFilter

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

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

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("ForEach-Allowed");

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

return new CorsWebFilter(source);
}

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

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

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

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

5. Вывод

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

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

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