Как включить CORS в проекте Spring 5 Webflux?
Я не могу найти правильную документацию.
Как включить CORS в проекте Spring 5 Webflux?
Я не могу найти правильную документацию.
Вот еще одно решение с конфигуратором Webflux.
Side Note: Код Kotlin (скопирован из моего проекта), но вы можете легко перевести это на Java-код.
@Configuration
@EnableWebFlux
class WebConfig: WebFluxConfigurer
{
override fun addCorsMappings(registry: CorsRegistry)
{
registry.addMapping("/**")
.allowedOrigins("*") // any host or put domain(s) here
.allowedMethods("GET, POST") // put the http verbs you want allow
.allowedHeaders("Authorization") // put the http headers you want allow
}
}
У меня был успех с этим настраиваемым фильтром:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsConfiguration {
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN";
private static final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
private static final String ALLOWED_ORIGIN = "*";
private static final String MAX_AGE = "3600";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers",ALLOWED_HEADERS);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
и org.springframework.boot:spring-boot-starter-web
не следует включать в качестве зависимости - фильтр не работает с ним.
@Configuration
public class WebFluxConfig {
@Bean
public WebFluxConfigurer corsConfigurer() {
return new WebFluxConfigurerComposite() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("*");
}
};
}
}
который соответствует:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
для весны mvc.
Благодаря @Dachstein замена WebMvc-конфигураций на Webflux - правильный способ добавления глобального CORS Config здесь.
@Configuration
@EnableWebFlux
public class CORSConfig implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*");
}
}
Вот ссылка на официальную документацию
https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-cors
Есть 3 основных варианта
1) Использование аннотации @CrossOrigin на контроллере отдыха - ее можно использовать на уровне класса и/или метода
2) Реализуйте метод addCorsMapping из WebFluxConfigurer - он дает вам возможность подключиться к глобальному объекту CorsRegistry
3) Определить компонент CorsWebFilter - хороший выбор для функциональных конечных точек
Пожалуйста, посмотрите на документы, они хорошо объяснены.
Лично я использую третий вариант, когда хочу разрешить использование cors во время разработки, и я отделил бэкэнд от модуля frontend.
Представьте, что у вас есть webflux на бэкэнд-модуле, в то время как на внешнем интерфейсе у вас есть приложение реакции или угловое приложение. При разработке функций веб-интерфейса вам может потребоваться использовать webpack-dev-server для горячей перезагрузки, в то время как бэкэнд еще работает на netty - порт будет другим, и это вызовет проблему CORS. С третьим вариантом вы можете легко связать @Component с @Profile ("dev"), чтобы при развертывании в prod CORS были включены.
Если кто-то хочет получить ответ Zufar на Kotlin (работает как шарм с функциями маршрутизации webflux), не разбираясь в том, как работают преобразования Kotlin SAM, вот код:
@Bean
fun corsFilter(): WebFilter {
return WebFilter { ctx, chain ->
val request = ctx.request
if (CorsUtils.isCorsRequest(request)) {
val response = ctx.response
val headers = response.headers
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN)
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS)
headers.add("Access-Control-Max-Age", MAX_AGE)
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS)
if (request.method === HttpMethod.OPTIONS) {
response.statusCode = HttpStatus.OK
[email protected] Mono.empty<Void>()
}
}
chain.filter(ctx)
}
}
ОБНОВЛЕНИЕ Поскольку я начал проверять это, я нашел одну проблему с этим решением. Это нормально, если вы действительно хотите разрешить все методы. Но представьте, что вы хотите разрешить только POST
и OPTIONS
, например. И браузер пытается отправить PUT
.
Тогда предпечатный ответ в основном скажет: "Эй, я могу обслуживать только POST и OPTIONS, но мой HTTP-статус будет в OK
если вы дадите мне запрос с Access-Control-Request-Method=PUT
". Это должно быть 403 Forbidden
однако. Более того, большинство из этих заголовков, таких как Access-Control-Allow-Methods
следует добавлять только к предварительным запросам, а не ко всем запросам CORS
. Решение:
@Bean
fun corsWebFilter(): CorsWebFilter {
val corsConfig = CorsConfiguration()
corsConfig.allowedOrigins = Arrays.asList(ALLOWED_ORIGINS)
corsConfig.maxAge = MAX_AGE.toLong()
//Notice it singular. Can't be comma separated list
corsConfig.addAllowedMethod(ALLOWED_METHOD)
corsConfig.addAllowedHeader(ALLOWED_HEADER)
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration(MATCH_ALL_PATH_SEGMENTS, corsConfig)
return CorsWebFilter(source)
}
где
const val MATCH_ALL_PATH_SEGMENTS = "/**"