Spring-cloud-gateway: Support for routing cross-origin OPTIONS requests

Created on 11 Feb 2019  路  11Comments  路  Source: spring-cloud/spring-cloud-gateway

It seems that it's currently not possible to route cross-origin OPTIONS requests with Spring Cloud Gateway to other backend services. This would be desirable so that the components serving the requests can decide on their own which CORS headers to return to their clients. As far as I know it's currently only possible to handle CORS within the gateway itself via a global configuration.

I've created a pull request in my forked repository that adds a failing test to the spring-cloud-gateway-sample application.

There's already been a discussion on the topic in #229 starting with this comment.

enhancement

Most helpful comment

I don't think that the PR for #840 accomplishes what this issue asks for. If I understand the PR correctly, it adds an option to apply the global configuration for requests that are not routed by the gateway. This feature request is about adding support for routing preflight requests to other backend services.

@tony-clarke-amdocs May I ask you to confirm this?

All 11 comments

Closing in favor of #840 that has a link to a PR

I don't think that the PR for #840 accomplishes what this issue asks for. If I understand the PR correctly, it adds an option to apply the global configuration for requests that are not routed by the gateway. This feature request is about adding support for routing preflight requests to other backend services.

@tony-clarke-amdocs May I ask you to confirm this?

Thanks for the clarification.

PRs welcome

+1

+1

Please stop commenting +1 and just add a thumbs up on the original comment

Faced this issue when tried to pass preflight request through API gateway.

The core of issue is AbstractHandlerMapping from webflux.
I just briefly observed webflux sources and still not so familiar with ideology but from the first look webflux processes OPTIONS (and looking deeper - preflights) in very specific way.

For me fix looks like the following:

public class GatewayCustomConfiguration extends GatewayAutoConfiguration {

    @Bean
    public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler,
                 RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {

        return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties, environment){

            public Mono<Object> getHandler(ServerWebExchange exchange) {
                Mono<Object> handler = getHandlerInternal(exchange).map((hndl) -> {return hndl;});
                return CorsUtils.isPreFlightRequest(exchange.getRequest()) ? handler : super.getHandler(exchange);
            }
        };
    }
}

and

spring.cloud.gateway.enabled = false

That works for me as hotfix but I don't like it because I cannot predict all drawbacks.

PRs welcome

@spencergibb Do you have an idea what you expect to be the real functional solution? Is it something as simple as a configuration option that (e.g. spring.cloud.gateway.globalcors.route=true) that does effectively what @A-n-d-r-e-i-P suggested?

Or perhaps RoutePredicateHandlerMapping could always pass the request to the handler, then a filter could be provided that allows for more fine grain control on a route by route basis. That feels maybe like the best approach.

I'm trying to understand what the most ideal solution would be that plays well with AbstractHandlerMapping?

Maybe the property name should be something like spring.cloud.gateway.globalcors.preflight.passthrough=true? (I've not looked into how to implement it yet)

Have the same problem. Use SpringBoot webflux and SpringCloud Gateway ,can't forward OPTIONS requests with Spring Cloud Gateway to out backend service.
So I overwite "org.springframework.web.cors.reactive.CorsUtils" class,
just make isPreFlightRequest always return false , that solved my problem.
```java
public static boolean isPreFlightRequest(ServerHttpRequest request) {
//HttpHeaders headers = request.getHeaders();
//return (request.getMethod() == HttpMethod.OPTIONS
// && headers.containsKey(HttpHeaders.ORIGIN)
// && headers.containsKey(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD));
return false;
}
````

Was this page helpful?
0 / 5 - 0 ratings