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.
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
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