3

I have a React application based on Typescript which is hosted on my PC. I use Spring gateway to forward requests to another microservice. GET requests are working fine but for POST requests I get:

Access to XMLHttpRequest at 'http://1.1.1.1:8080/api/support/tickets/create' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I'm hitting this Spring Cloud Gateway issue: https://github.com/spring-cloud/spring-cloud-gateway/issues/229

Spring cloud configuration:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder, LoggingGatewayFilterFactory loggingFactory) {
    return builder.routes()
            .route("route_id",
                    route -> route
                            .path("/api/support/tickets/**")
                            .filters(f -> f.rewritePath("/api/support/tickets/(?<RID>.*)", "/support/tickets/${RID}"))
                            .uri("lb://merchant-hub-admin-service")
            )
            .build();
}

React code:

export async function getTicket(id: string) {
  return await axios.get(`${baseUrl}/support/tickets/ticket/${id}`);
}

export async function postTicket(
  data: TicketFullDTO
): Promise<AxiosResponse<TicketFullDTO>> {
  return await axios.post<TicketFullDTO>(
    `${baseUrl}/support/tickets/create`, data);
}

This is caused by buy-in Spring Cloud Gateway: https://github.com/spring-cloud/spring-cloud-gateway/issues/2472

I tried to implement this workaround:

@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 it's not working. Do you know how I can solve this issue?

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
Peter Penzov
  • 1,126
  • 134
  • 430
  • 808
  • Have you configured the gateway for CORS? From the Github link it looks like there are some workarounds to set the allowed methods. – GenericUser Jan 09 '22 at 02:04
  • Yes, I tried but it's not solving the issue. – Peter Penzov Jan 09 '22 at 02:05
  • What response headers does postman or something similar show on a post request? – kevinSpaceyIsKeyserSöze Jan 09 '22 at 07:18
  • See this picture: https://ibb.co/gmQBYvW – Peter Penzov Jan 09 '22 at 08:15
  • I... it could be that I'm blind, but I don't see any `Access-Control-Allow-Origin` headers... – Elias Jan 30 '22 at 14:46
  • An easy test would be to set the header to: `*`, and check to see if it works. After that you could restrict access to your domain only. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin – Elias Jan 30 '22 at 14:48
  • I have no idea what "spring-cloud-gateway" is, but I would argue that you should set that header on the micro-service, not on the gateway, no? If not, you should (however that works), add that header inside the gateway in the response. – Elias Jan 30 '22 at 14:54
  • Maybe this is a relevant question: https://stackoverflow.com/a/51666685/10315665? – Elias Jan 30 '22 at 14:56
  • your frontend is localhost:3000 and someone is on 1.1.1.1:8080 throwing this error. So into your API code check your spring configuration you have to give permissions to be requested from your browser origin: localhost:3000. I think the CORS issue is coming from the API, you should first go to the API code and see spring config to check the gateway can access it, look at access-control-*** headers. Other way to see this issue would be, skip the gateway and point your frontend to the original API URL if that works means your issue is in the gateway. – guiwme5 Jan 30 '22 at 23:47
  • Yes but they are hosted on separate machines. CORS blocks requests when they are on the same machine. – Peter Penzov Jan 31 '22 at 00:31
  • Cors cares about domains, not about machines. – Mordechai Jan 31 '22 at 06:20

2 Answers2

3

Actually, CORS is a browser feature and you can disable it in the development area.

The browser should call an OPTIONS for non-matched URLs (website URL & API URL) when these two aren't matched, the browser must call an OPTIONS call to Backend API to get allowed to continue, for production if your website URL and API are not matched you should ask your Backend or DevOps guys to settle it up but for the development area there a couple of things you can do:

  • if you are using CRA, the previous answer can help you.

  • if you are using custom configuration and you have a Webpack config file, add this line to your Webpack and it can help you:

    module.exports = {
      devServer: {
        proxy: 'http://1.1.1.1:8080',
      },
    
  • another cute way is directly disabling security in your Chrome to have an easy development, put these commands in their related OS and run, you will run a new instance of chrome without security (without OPTIONS call):

    ## macOS
    open -na Google\ Chrome --args --user-data-dir=/tmp/temporary-chrome-profile-dir --disable-web-security --disable-site-isolation-trials
    
    ## windows
    chrome.exe --disable-web-security
    
    ## linux
    google-chrome --disable-web-security
    

For more information about the last item, you can read this post.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
2

It seems that your issue is about local development only.

Create react app solves precisely this by supporting the dev server to serve as a proxy to your API endpoint.

Just add the API domain in the proxy key in package.json. More on this here

For production you should either host them both under the same domain (using a reverse proxy to route static content vs api request based on the URL path), or find a permanent cors friendly solution on your backend.

Cors is a browser feature and cannot be disabled. Though, when not using the POST method you can get around the preflight but you still can't access the response body without the proper headers set

Mordechai
  • 15,437
  • 2
  • 41
  • 82