为什么我的Servlet过滤器会运行两次?

时间:2016-09-05 21:36:39

标签: servlets java-ee intellij-idea servlet-filters embedded-jetty

我有一个简单的Servlet过滤器:

package net.twentyonesolutions;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;

public class TestFilter implements Filter {

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println(TestFilter.class.getSimpleName()       // line 12
                + " > "
                + ((HttpServletRequest)servletRequest).getRequestURL()
                + ": IP "+ servletRequest.getRemoteAddr()
                + "; at "
                + new Date().toString());

        // Pass request back down the filter chain
        filterChain.doFilter(servletRequest, servletResponse);    // line 20
    }

    public void init(FilterConfig filterConfig) throws ServletException {}

    public void destroy() {}
}

我将它添加到web.xml中,如下所示:

<filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>net.twentyonesolutions.TestFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>TestFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

我在IntelliJ IDEA的调试模式下使用嵌入式Jetty运行它。我希望第12行的输出写入一次,但是它被写入两次,并且两次都在Servlet被调用之前。

为什么要两次打电话?应该被叫两次吗?如果是这样,我怎么能从第二次第一次告诉,因为我希望我的代码只运行一次。

我发现了一些关于这个问题的老问题,但没有一个有真正的解决方案或解释。

您可以在下面的屏幕截图中看到第一个电话和第二个电话之间的堆栈跟踪差异:

enter image description here

更新

当我将过滤器部署到常规(非嵌入式)Jetty(与嵌入式版本9.2.18.v20160721相同的版本)或Tomcat - doFilter()时,每个请求只执行一次,如预期的那样,所以问题在于IntelliJ IDEA中的调试或嵌入式Jetty。

更新嵌入代码:

    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setResourceBase(webRoot);
    webapp.setDefaultsDescriptor(webRoot + "/WEB-INF/web.xml");     

    Server server = new Server();

    ServerConnector http = new ServerConnector(server);
    http.setPort(port);             
    if (!host.equals(""))
        http.setHost(host);

    server.setConnectors(new ServerConnector[] { http });
    server.setHandler(webapp);      
    server.start();
    server.join();

更新filterChain.toString()

我在调用filterChain.doFilter()之前添加了filterChain.toString()的打印件,它清楚地显示了差异。

filterChain中的第一个对象(在第一次调用doFilter()之前)是我的过滤器。见两条印刷线:

TestFilter > fdvnqp1k0ut37fenee569vshqf http://localhost:8080/index.cfm: IP 0:0:0:0:0:0:0:1; at Tue Sep 06 09:59:09 PDT 2016
    ... filterChain: TestFilter->CFMLServlet@cdad6a3==lucee.debug.loader.servlet.CFMLServlet,1,true
TestFilter > fdvnqp1k0ut37fenee569vshqf http://localhost:8080/index.cfm: IP 0:0:0:0:0:0:0:1; at Tue Sep 06 09:59:09 PDT 2016
    ... filterChain: CFMLServlet@cdad6a3==lucee.debug.loader.servlet.CFMLServlet,1,true

我对规格不确定,但我希望在第一次调用TestFilter之前将我的TestFilter.doFilter()从链中删除,不是吗?

1 个答案:

答案 0 :(得分:5)

我认为问题在于您将WEB-INF / web.xml设置为默认描述符。所以web.xml运行了两次 - 一次设置默认值,一次设置为发现的WEB-INF / web.xml - 所以你得到两个过滤器实例。

不要设置默认描述符(或者如果你想知道默认值,则将其设置为null - 但是你不会有默认的servlet)。

相关问题