Allow streaming of multipart requests in Zuul proxy

It turns out that the suckiness of Zuul with multipart requests
comes almost entirely from the Multipart handling in Spring's
DispatcherServlet. This change makes the proxy routes available
on an alternative path /zuul/<normal_path> (where
/zuul is the default value of zuul.servletPath). I have
tested those with 800MB file uploads using the main method in
the FormZuulServletProxyApplicationTests and the main
observation is that there is no OutOfMemory error (no-one tries
to download the complete request body). It works with Ribbon
and with the simple (HttpClient) filter. With Ribbon you
will need to set some timeouts if you want to upload files
as large as that, e.g. see application.yml in the tests:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000

You need to set "Transfer-Encoding: chunked" in the
incoming request. Chrome does not do this by default
apparently, but I was able to test with curl, e.g.

$ curl -v -H "Transfer-Encoding: chunked" \
  -F "file=@mylarg.iso" \
  localhost:9999/zuul/direct/file

The old proxy paths through the DispatcherServlet are still
available (for backwards compatibility and for convenience of
having the paths available at the root of the context path).

Fixes gh-254
This commit is contained in:
Dave Syer
2015-03-13 16:35:46 +00:00
parent da4f5d3454
commit 0391cfff65
8 changed files with 322 additions and 6 deletions

View File

@@ -860,6 +860,37 @@ An application with the `@EnableZuulProxy` could act as a standalone
server if you set a default route ("/"), for example `zuul.route.home:
/` would route all traffic (i.e. "/**") to the "home" service.
=== Uploading Files through Zuul
If you `@EnableZuulProxy` you can use the proxy paths to
upload files and it should just work as long as the files
are small. For large files there is an alternative path
which bypasses the Spring `DispatcherServlet` (to
avoid multipart processing) in "/zuul/*". I.e. if
`zuul.routes.customers=/customers/**` then you can
POST large files to "/zuul/customers/*". The servlet
path is externalized via `zuul.servletPath`. Extremely
large files will also require elevated timeout settings
if the proxy route takes you through a Ribbon load
balancer, e.g.
.application.yml
[source,yaml]
----
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 60000
----
Note that for streaming to work with large files, you need to use chunked encoding in the request (which some browsers
do not do by default). E.g. on the command line:
----
$ curl -v -H "Transfer-Encoding: chunked" \
-F "file=@mylarge.iso" localhost:9999/zuul/simple/file
----
=== Plain Embedded Zuul
You can also run a Zuul server without the proxying, or switch on parts of the proxying platform selectively, if you