Multipart配置无法在奇怪的情况下为动态添加的servlet工作

Fag*_*ack 8 java jboss jsp servlets java-ee

JSP:

<!DOCTYPE html>
<form action="/{insert your context here}/p/hello" method="post" enctype="multipart/form-data">
  <input type="file" name="data">
  <button>Go</button>
</form>
Run Code Online (Sandbox Code Playgroud)

Servlet的:

@WebServlet
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1;
    @Override
    protected void doPost( HttpServletRequest request, HttpServletResponse response )
    throws IOException, ServletException {
        if ( request.getPart( "data" ) != null ) {
            response.getWriter().print( "It worked\n\n" );
        } else {
            response.getWriter().print( "IT IS NOT WORKING!\n\n" );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

过滤

@WebFilter( filterName = "hello" )
public class HelloFilter implements Filter {
    @Override
    public void init( FilterConfig config ) throws ServletException {}

    @Override
    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
    throws IOException, ServletException {
        request
            .getRequestDispatcher( "/hello" )
            .include( request, response );

        request
            .getRequestDispatcher( "/hello.jsp" )
            .include( request, response );
    }

    @Override
    public void destroy() {}
}
Run Code Online (Sandbox Code Playgroud)

倾听者

@WebListener
public class HelloListener implements ServletContextListener {
    @Override
    public void contextInitialized( ServletContextEvent event ) {
        ServletContext context = event.getServletContext();
        Dynamic hello = context.addServlet( "hello", HelloServlet.class );
        hello.addMapping( "/hello" );
        hello.setMultipartConfig( getMultiPartConfig() );
    }
    @Override
    public void contextDestroyed( ServletContextEvent event ) {}

    private MultipartConfigElement getMultiPartConfig() {
        String location = "";
        long maxFileSize = -1;
        long maxRequestSize = -1;
        int fileSizeThreshold = 0;
        return new MultipartConfigElement(
            location,
            maxFileSize,
            maxRequestSize,
            fileSizeThreshold
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

我的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>{insert the context here}</display-name>
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
  </jsp-config>
  <filter-mapping>
    <filter-name>hello</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>
Run Code Online (Sandbox Code Playgroud)

当我提交表单时,我收到输出"它不工作!" 在答复的第一行.如果我改变从请求的路径/{insert your context here}/p/hello,以/{insert your context here}/hello它的工作原理,为什么呢?

使用:
JBoss EAP 6.1

Bar*_*man 2

我能够使用 Tomcat 7.0.30 重现该问题。无论我使用注释动态还是静态配置“HelloServlet”,都存在同样的问题@MultipartConfig

我还在 Jetty 版本 8.1.13.v20130916 上进行了测试,两种情况下都运行良好;/{context}/p/hello/{context}/hello,不做任何修改。

如果你要HelloListener这样修改:

Dynamic hello = context.addServlet( "hello", HelloServlet.class );
hello.addMapping( "/hello" );
hello.addMapping( "/p/hello" );
hello.setMultipartConfig( getMultiPartConfig() );
Run Code Online (Sandbox Code Playgroud)

它会起作用,但我怀疑这违背了你想要做的事情的目的。另一种选择是修改过滤器以根据需要动态添加新映射:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    // dynamically add mappings
    ServletContext context = request.getServletContext();
    ServletRegistration registration = context.getServletRegistration("hello");
    registration.addMapping("/<dynamic path>/hello");

    request.getRequestDispatcher("/hello").include(request, response);
    request.getRequestDispatcher("/hello.jsp").include(request, response);
}
Run Code Online (Sandbox Code Playgroud)

似乎 tomcat/jboss 仅根据原始请求路径是否启用对请求的多部分支持是否与为多部分支持配置的 servlet 之一匹配来启用请求的多部分支持,而它应该根据当前正在处理的请求的路径启用支持(它可能已被 RequestDispatcher“包含”。

它看起来确实像一个 tomcat/jboss bug,但你必须仔细阅读 servlet 规范才能找到答案,否则你可以使用 Jetty 来代替。