向不存在的Servlet发送Multipart请求:JEE的Bug还是特性?
JEE中Multipart请求转发后参数丢失的原因及规范依据
现象
- 当表单action指向不存在的Servlet URL,发送Multipart请求后,即使通过Filter转发到配置了
@MultipartConfig的Servlet,该Servlet调用request.getParameterMap()返回空Map,request.getParts()返回空集合。
环境配置
- 全局Filter拦截所有请求:
@WebFilter("/*") public class Filter extends HttpFilter {
- 两个配置
@MultipartConfig的Servlet:
@WebServlet("/servA") @MultipartConfig( fileSizeThreshold = 1024 * 1024 * 1, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 50 ) public class ServletA extends HttpServlet {
@WebServlet("/servB") @MultipartConfig( fileSizeThreshold = 1024 * 1024 * 1, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 50 ) public class ServletB extends HttpServlet {
测试过程
- 通过
chain.doFilter传递请求- 表单action指向存在的Servlet,Filter调用
chain.doFilter,Servlet可正常获取参数和Parts; - 表单action指向不存在的Servlet,返回404,符合预期。
- 表单action指向存在的Servlet,Filter调用
- 通过
requestDispatcher.forward转发请求- 表单action指向存在的Servlet,Filter转发至任意配置了
@MultipartConfig的Servlet,均可正常获取参数和Parts; - 表单action指向不存在的Servlet,Filter转发至
/servA或/servB,两个Servlet均无法获取参数和Parts。
- 表单action指向存在的Servlet,Filter转发至任意配置了
原因分析(基于Servlet 3.0+规范)
Servlet规范中,Multipart请求的解析时机由初始请求匹配的目标Servlet决定:
- 容器接收到请求时,首先匹配请求URL对应的Servlet。如果该Servlet配置了
@MultipartConfig,容器会自动将请求解析为Multipart格式,生成对应的Parts和参数; - 如果初始请求的URL没有匹配到任何Servlet(即404场景),容器不会触发Multipart解析逻辑,请求会被当作普通HTTP请求处理。此时即使后续通过Filter转发到配置了
@MultipartConfig的Servlet,容器也不会重新解析请求体——因为请求输入流只能被读取一次,且解析时机已经错过,转发后的Servlet无法从已处理的请求中提取Parts和参数。
Tomcat、GlassFish等主流容器均严格遵循这一规范,因此该表现属于规范定义的预期行为,而非Bug。
临时解决方案
新增一个映射为/*的Servlet并配置@MultipartConfig(可禁止直接访问),确保所有初始请求都能匹配到启用Multipart解析的Servlet:
@WebServlet("/*") @MultipartConfig( fileSizeThreshold = 1024 * 1024 * 1, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 50 ) public class ServletM extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 禁止直接访问,可转发到其他业务Servlet req.getRequestDispatcher("/servA").forward(req, resp); } }
内容的提问来源于stack exchange,提问作者telos
相关产品推荐
相关产品推荐

