Describe the bug
We have a downstream service with a multipart request endpoint for file upload
Zuul starts to proxy the request, the embedded tomcat in Spring rejects it and throws an exception because it exceeds the spring.servlet.multipart.max-file-size, however Zuul hits /error in the downstream. The original request was a POST request so the /error was called with POST
Another strage behaviour I noticed is that if I handle the MaxUploadSizeExceededException in a @ControllerAdvice then the return value becomes the URL sent downstream. eg) in the below case the url hit in downstream is POST /upload-error
// Downstream called with `/upload-error`
@ExceptionHandler(MaxUploadSizeExceededException.class)
public String handleFileSizeException(MaxUploadSizeExceededException err) {
log.error("File is too large", err);
return "upload-error";
}
And this seems to be not specific to MaxUploadSizeExceededException, we noticed the same behaviour when for a SocketTimeoutException, so this seem to happen whenever an Exception is thrown
Can you suggest a possible work around for this?
Possible Behaviour
- Request to be rejected with 500, without requesting /error in downstream
Dependencies:
ext {
set('springCloudVersion', "Hoxton.BUILD-SNAPSHOT")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
}
Repo Reproducing the Issue https://github.com/Mark1626/Paraphernalia/tree/master/spring-proxy-multipart
cc @spencergibb
Comment From: spencergibb
Zuul doesn't make multiple requests downstream. It looks to me that tomcat is changing the request to /error before it gets to zuul. Your proxying everything /** so it all gets proxied. Can you tighten the paths that get proxied?
Comment From: Mark1626
Changing from the /** routes to somthing more strict
zuul:
routes:
tomcat:
path: /upload
url: http://localhost:8080
After changing the route it does not make the /error call. How does this work under the box?
Comment From: Mark1626
I also want to callout another thing, this is from the documentation
zuul:
routes:
users:
path: /myusers/**
legacy:
path: /**
We have a similar usecase with some legacy systems, which is why I had the route as /** initially. Is there a way to handle this without changing the route?
https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html#netflix-zuul-reverse-proxy
Comment From: spencergibb
I'm unsure what "How does this work under the box?" mean?
/** will proxy the error unless there is another route that matches /error.
Comment From: yyvess
@spencergibb I confirm the issue, requests are executed twice to downstream on version Hoxton-SR8.
That happen as example after a socket timeout on a backend call.
I suspect that issue is new without to be able to identify the change related to this issue.
My analysis: When no error handlers is setup the class ZuulHandlerMapping forward the request to the backend.
As the PreDecorationFilter is not re-executed, the requestURI value on the RequestContext.getCurrentContext() contains the original Uri and not the Uri /error. That cause the execution of a second call to the backend on the original URI !
I hop that issue can easily fixed on ZuulHandlerMapping.java by adding a check on the key "sendErrorFilter.ran" or the context must be updated with the correct uri.
if (ctx.containsKey("forward.to") || ctx.containsKey("sendErrorFilter.ran") ) {
return null;
As workaround you can setup an error handler or add this configuration:
error.path: /zuul-error
zuul:
ignored-patterns:
- /zuul-error
Comment From: OlgaMaciaszek
@Mark1626 @yyvess Please provide a minimal, complete, verifiable example that reproduces the issue.
Comment From: spring-cloud-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-cloud-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.