Skip to content

The OPTIONS request cannot be forwarded to the service #2472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
DawnSouther opened this issue Dec 25, 2021 · 19 comments · May be fixed by #2582
Open

The OPTIONS request cannot be forwarded to the service #2472

DawnSouther opened this issue Dec 25, 2021 · 19 comments · May be fixed by #2582
Labels

Comments

@DawnSouther
Copy link

DawnSouther commented Dec 25, 2021

Describe the bug
Because I have a service proxied by the gateway, this service needs to customize the response header of the OPTIONS request, but I found that the gateway does not send the request to my service

I found that when the preflight request passes through the gateway, the request header contains both Origin and Access-Control-Request-Method, it will enter NO_OP_HANDLER and will not access the route defined by the RouteDefinition.
Does the cors of the gateway refer to intercepting the request and returning it directly?
If so, is there a way to remove the cors filter of the gateway? Or can you briefly talk about why it is designed like this?

image
image

Version
[email protected]

Config

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOriginPatterns: '*'
            allowedMethods: '*'
            allowedHeaders: '*'
            allowCredentials: true
      default-filters:
          - DedupeResponseHeader=Vary Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST
@rcbandit111
Copy link

Any plans to fix this soon?

@rcbandit111
Copy link

@DawnSouther Can you propose some quick code fix, please? I'm blocked from this issue.

@rcbandit111
Copy link

Any update on this?

@rcbandit111
Copy link

@spencergibb is it possible to fix this issue soon? Unfortunately it's blocking my project.

@spencergibb
Copy link
Member

PRs welcome. The earliest release will by next month.

@DawnSouther
Copy link
Author

DawnSouther commented Jan 29, 2022

@DawnSouther Can you propose some quick code fix, please? I'm blocked from this issue.

@rcbandit111 Sorry, just saw this.
There is a temporary solution, I extracted part of the logic that needs to respond to OPTIONS and put it on the gateway separately.
Like this, load a custom CorsProcessor in the RoutePredicateHandlerMapping.

    @Bean
    public RoutePredicateHandlerMapping tusRoutePredicateHandlerMapping(FilteringWebHandler webHandler,
                                                                        RouteLocator routeLocator,
                                                                        GlobalCorsProperties globalCorsProperties,
                                                                        Environment environment) {
        RoutePredicateHandlerMapping routePredicateHandlerMapping = new RoutePredicateHandlerMapping(webHandler,
                routeLocator, globalCorsProperties, environment);
        routePredicateHandlerMapping.setCorsProcessor(new TusCorsProcessor());
        return routePredicateHandlerMapping;
    }

@DawnSouther
Copy link
Author

PRs welcome. The earliest release will by next month.

Before formally solving this problem, I think I should listen to your ideas first, or I just need to mention a pr that ignores the interception of cors in the gateway?

@rcbandit111
Copy link

@DawnSouther I want to test your temporary solution. Can you share what is the content of TusCorsProcessor?

@DawnSouther
Copy link
Author

@DawnSouther I want to test your temporary solution. Can you share what is the content of TusCorsProcessor?

Of course.

public class TusCorsProcessor extends DefaultCorsProcessor {

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public boolean process(@Nullable CorsConfiguration config, ServerWebExchange exchange) {
        // 添加tus头
        String contextPath = exchange.getRequest().getURI().getRawPath();
        if (!StrUtil.endWith(contextPath, "/")) {
            contextPath = contextPath + "/";
        }
        if (antPathMatcher.match(TusConsts.TUS_PATTERN, contextPath)) {
            this.applyTusHeader(exchange.getResponse());
        }

        return super.process(config, exchange);
    }

    private void applyTusHeader(ServerHttpResponse response) {
        HttpHeaders headers = response.getHeaders();
        headers.add(TusConsts.ACCESS_CONTROL_EXPOSE_HEADER, TusConsts.ACCESS_CONTROL_EXPOSE_OPTIONS_VALUE);
        headers.add(TusConsts.TUS_RESUMABLE_HEADER, TusConsts.TUS_RESUMABLE_VALUE);
        headers.add(TusConsts.TUS_VERSION_HEADER, TusConsts.TUS_VERSION_VALUE);
        headers.add(TusConsts.TUS_MAX_SIZE_HEADER, TusConsts.TUS_MAX_SIZE.toString());
        headers.add(TusConsts.TUS_EXTENTION_HEADER, TusConsts.TUS_EXTENTION_VALUE);
        response.setStatusCode(HttpStatus.OK);
    }
}

@rcbandit111
Copy link

@DawnSouther Can you share also what are the imports for this class? I can't find imports for StrUtil and TusConsts.

@rcbandit111
Copy link

rcbandit111 commented Jan 30, 2022

@DawnSouther I tried this:

    @Bean
    public RoutePredicateHandlerMapping tusRoutePredicateHandlerMapping(FilteringWebHandler webHandler,
                                                                        RouteLocator routeLocator,
                                                                        GlobalCorsProperties globalCorsProperties,
                                                                        Environment environment) {
        RoutePredicateHandlerMapping routePredicateHandlerMapping = new RoutePredicateHandlerMapping(webHandler,
                routeLocator, globalCorsProperties, environment);
        routePredicateHandlerMapping.setCorsProcessor(new CrackCorsProcessor());
        return routePredicateHandlerMapping;
    }

........

import org.springframework.lang.Nullable;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.DefaultCorsProcessor;
import org.springframework.web.server.ServerWebExchange;

public class CrackCorsProcessor extends DefaultCorsProcessor {

    @Override
    public boolean process(@Nullable CorsConfiguration config, ServerWebExchange exchange) {
        return false;
    }
}

But OPTIONS request is not forwarded again properly. @spencergibb can you also advise please how I can make a quick fix for this issue?

@DawnSouther
Copy link
Author

@rcbandit111 I put the logic to be processed by options on the gateway

@rcbandit111
Copy link

@DawnSouther Sorry I don't get it. Can you show me code example, please?

@spencergibb
Copy link
Member

I don't have any quick fix for this. The code in your screenshots is from Spring Framework and not Gateway. It looks like we might need a custom CorsProcessor, but I'm not familiar with that bit of framework. I'll need to work with @rstoyanchev

@rcbandit111
Copy link

Thanks, waiting for fix.

@rstoyanchev
Copy link

rstoyanchev commented Mar 3, 2022

@spencergibb the general idea is that Spring WebFlux has built-in support for pre-flight requests, so it only finds the matching handler for the "would-be" (actual) request, then updates the response accordingly, and shortcircuits.

Keep in mind that pre-flight requests are not authenticated. This why they're handled even earlier in Spring Security, which finds a PreFlightHandler bean (implemented by DispatcherHandler) and calls it to handle pre-flight requests and then skip the rest of the filter chain which would pose a risk in case some unexpected handling took place.

To handle pre-flight requests by passing them through, you'll need some similar approach, intercept early via WebFilter, and not allow it to continue down the WebFilter chain.

@DawnSouther
Copy link
Author

@rstoyanchev Thanks for your explanation.
I understand your idea. It is necessary and important to consider security, but the requests proxyed by our spring gateway are not only GET, POST..., but also other types of requests (pre-flight requests). Or it can be said that the services proxied by spring gateway are not only spring-web, but also other types of services.

Maybe we can add a switch to it to control the cors filter(stragegy?) of spring gateway? Allow cors requests to be forwarded to the target service through spring gateway, fully controlled by the target service.
Instead of just short-circuiting the pre-flight as it does now.

For example, I have a very practical scenario where I need to be a server that supports the tus protocol, and the tus protocol needs to respond to the options method and add headers to the response to determine the tus-version, tus-extension. . . . . . I checked a lot of places at the time, and it wasn't until the end that it was determined that the problem was caused by the spring gateway. hahaha......It's a real headache

I think spring gateway is first of all a gateway, at least to achieve forwarding, security and other functions can not affect the forwarding

tommas1988 added a commit to tommas1988/spring-cloud-gateway that referenced this issue Apr 10, 2022
@tommas1988 tommas1988 linked a pull request Apr 10, 2022 that will close this issue
@lgscofield
Copy link

@DawnSouther
Maybe U should add this:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
in U classpath, then U yml configuration file will work

@alexmntmnk
Copy link

Is there any solution to this problem at the moment? Or how to get around it?

tommas1988 added a commit to tommas1988/spring-cloud-gateway that referenced this issue Nov 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants