javaspring-boottomcatspring-cloud-gateway

Spring Cloud Gateway returning HTML error instead of relaying service error


I'm using Spring Cloud Gateway (MVC) as a BFF between my frontend(SPA) and backend. Everything works as expected, but if the backends returns an error (e.g. 409), the gateway returns 500 with HTML as a response.

Digging deeper I find the following error:

2024-10-23T16:30:47.804+02:00 ERROR 31792 --- [edepot-api-gateway] [nio-7081-exec-6] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing [ErrorPage[errorCode=0, location=/error]]

jakarta.servlet.ServletException: Request processing failed: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:4200/error": http://localhost:4200/error

which is caused by:

java.io.FileNotFoundException: http://localhost:4200/error

But the error from the backend is correctly received (logs before the above):

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/api/x": Server returned HTTP response code: 409 for URL: http://localhost:8080/api/x

I wonder if it has something to do with Tomcat error handling, or mis configuration of the Gateway? It's weird that it returns HTML and not JSON.

Error message displayed

Here's my Gateway config:

spring.cloud.gateway.mvc.routes[0].id=api
spring.cloud.gateway.mvc.routes[0].uri=${backend-uri}
spring.cloud.gateway.mvc.routes[0].predicates[0]=Path=/api/**
spring.cloud.gateway.mvc.routes[0].filters[0].name=DedupeResponseHeader
spring.cloud.gateway.mvc.routes[0].filters[0].args[name]=Access-Control-Allow-Credentials Access-Control-Allow-Origin
spring.cloud.gateway.mvc.routes[0].filters[1].name=TokenRelay

//spring.cloud.gateway.mvc.routes[1] irrelevant

#Frontend routes
spring.cloud.gateway.mvc.routes[2].id=frontend
spring.cloud.gateway.mvc.routes[2].uri=${frontend-uri}
spring.cloud.gateway.mvc.routes[2].predicates=Path=/**
# Forwarding support
spring.cloud.gateway.mvc.http-client.type=autodetect
spring.cloud.gateway.mvc.http-client.connect-timeout=60s
spring.cloud.gateway.mvc.http-client.read-timeout=60s
#spring.cloud.mvc.discovery.enabled=true


Solution

  • Seems like the default JDK HttpClient wasn't working correctly. And the HttpUrlConnection was used because of the following configuration.

    Make sure this isn't configured:

    spring.cloud.gateway.mvc.http-client.type=autodetect
    

    If it still doesn't work (As I had forwarding issues with the default HttpClient) you can use an alternative client:

    application.properties:

    spring.cloud.gateway.mvc.http-client.type=autodetect
    

    pom.xml:

         <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
        </dependency>
    

    More information: Bug report for Spring Cloud Gateway MVC 4.1.5