zuul上传大文件 Processing of multipart/form-data request failed. Stream ended unexpec

先贴报错

image.png

因为我使用了 MultipartFile 作为文件上传的接收入参,前端通过请求网关,网关路由请求到后端服务,导致后端服务接受流失败意外结束
具体报错信息:

Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. Stream ended unexpectedly
复制代码

我看了好多网上的帖子,有说是tomcat的bug,说是要将tomcat升级到9.33+的版本(我用的是8.5的),有说是tomcat配置连接超时等说法的,全部试下来发现并没有解决问题

不通过网关,直接调用后端接口是可以上传文件成功,通过zuul上传则会导致流异常关闭,于是定位网关问题通过debug源码的方式来追溯问题

首先zuul网关的核心类是 com.netflix.zuul.http.ZuulServlet 将debug放在 zuulServlet

image.png

preRoute:就是我们继承 zuulfilter 后 通过filterType分为路由前、路由后、异常路由等

image.png

通过痛苦的追溯源码,发现当tomcat接受到请求后,封装为 HttpServletRequest,和通过层层过滤后到达zuulServletHttpServletRequest 请求头信息不同了

图一为tomcat封装的 HttpServletRequest

image.png
(图一)

图二为当请求到达 zuulServlet 的时候,获取到的 HttpServletRequest

image.png
(图二)

由此判断从tomcat到 zuulServlet 之间有环节篡改了 HttpServletRequest , 经过堆栈信息的调试,定位问题在于我依赖的一个组件,该组件有一个过滤器 实现了 OncePerRequestFilter , 在这个过程中他通过 HttpServletRequestWrapper 重写了请求头,并将重写后的请求头放入后续的过滤链

image.png

因为文件上传是通过流的方式,同时流的特性是读过一次就没有了,该组件在重写 HttpServletRequest 的时候读了流,导致 zuul 后续路由请求到后端服务的时候,后段服务的tomcat发现 Content-Type:multipart/form-data 类型,开始读流读不到,就会导致最开始的贴图的报错

image.png

后端服务tomcat源码报错的位置

image.png

总结

请求在前面的流程中已经被读取处理了,流是不可重复读取的,这意味着zuul在转发这个Request的时候,已经丢失了原本的内容,因此需要把放回去。这也是开发spring cloud gateway的原因之一,因为它没有这些问题

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享