doFilter called twice, intended behaviour?

后端 未结 8 1593
孤街浪徒
孤街浪徒 2021-02-19 16:42

I\'m working through the Java EE servlet tutorial and tried the mood example. I noticed the doFilter is getting called twice, once the servlet call is in the chain and the secon

相关标签:
8条回答
  • 2021-02-19 16:49

    I solved the same issue after removing @Component in CustomFilter class.

    0 讨论(0)
  • 2021-02-19 16:52

    I came across the same issue when the doFilter is called twice (or multiple times). The problem was that the filter handles every request including css, js, image and all other files while I expected one request for each page, so I solved the issue by adding the following code:

    @WebFilter(filterName = "MyCustomFilter")
    public class MyCustomFilter implements Filter {
    
      public void doFilter(ServletRequest request,ServletResponse response,
              FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String accept = httpRequest.getHeader("accept");
    
        // Since the filter handles every request
        // we have to ensure that the request is asking for text/html
        if (accept == null || !accept.toLowerCase().startsWith("text/html")) {
          chain.doFilter(request, response);
          return;
        }
    
        // your code goes here
    

    Hope this will help people like me who googled this question .

    0 讨论(0)
  • 2021-02-19 16:54
    chain.doFilter(request,response);
    

    This will pass the control to the servlet the filter is associated with. But after the corresponding servlet is executed, the control comes back at the end of the above line and all the lines thereafter in the current doFilter() is executed.

    If you want to pass the control permanently to the servlet and not letting it return to the filter, just add a

    return;
    

    at the end of chain.doFilter(request,response) line in the current filter.

    0 讨论(0)
  • 2021-02-19 17:01

    The Filter.doFilter method is called once per request. You can execute some code before other filters in the chain are called and also afterwards (in the order specified in the filter chain, as per the web.xml filter-mapping order), something like the following example:

    public MyFilter implements Filter {
        public void doFilter(ServletRequest request, ServletResponse response,
               FilterChain chain) 
               throws IOException, ServletException
        {
            codeToExecuteBeforeOtherFiltersInTheChain(request, response);
    
            chain.doFilter(request, response);
    
            codeToExecuteAfterOtherFiltersInTheChain(request, response);
    
        }
    }
    

    If your filter is configured to dispatch REQUEST and FORWARD requests, then the MyFilter.doFilter method will be called once for the original request and once if the request has been forwarded:

    Configure filter mapping using web.xml file:

    ...
    <filter-mapping>
          <filter-name>MyFilter</filter-name>
          <url-pattern>/*</url-pattern>
          <dispatcher>REQUEST</dispatcher>
          <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    ...
    

    Configure filter mapping using @WebFilter annotation:

    @WebFilter(urlPatterns = "/*", dispatcherTypes = {
        DispatcherType.REQUEST, DispatcherType.FORWARD
    }) public MyFilter implements Filter {
        ...
    }
    

    To be able to check if the request has been forwarded, you can use the request attribute described here: How to know when the request is forwarded in a RequestWrapper object

    For details about filters see: https://docs.oracle.com/cd/B32110_01/web.1013/b28959/filters.htm

    0 讨论(0)
  • 2021-02-19 17:03

    The reason why the filter is called twice are the images used in the response creation, as for instance

    out.println("<img src=\"resources/images/duke.snooze.gif\" alt=\"Duke sleeping\"/><br/>");
    

    Please see the log output

    2016-01-16T11:25:34.894+0100|Info: TimeOfDay doFilter method before sending to chain
    
    2016-01-16T11:25:34.895+0100|Info: MoodServlet get method called
    
    2016-01-16T11:25:34.895+0100|Info: TimeOfDay doFilter method after sending to chain
    
    2016-01-16T11:25:34.942+0100|Info: TimeOfDay doFilter method before sending to chain
    
    2016-01-16T11:25:34.942+0100|Info: TimeOfDay doFilter method after sending to chain
    

    src in img tag is nothing else than the second request for server to take care of. Please notice the url pattern used in the @WebFilter

    @WebFilter(filterName = "TimeOfDayFilter",
    urlPatterns = {"/*"},
    initParams = {
        @WebInitParam(name = "mood", value = "awake")})
    

    It will intercept all the requests coming into mood application. As an exercise simply try to remove images from the response or change url pattern to intercept only requests ending up in MoodServlet

    @WebFilter(filterName = "TimeOfDayFilter",
    urlPatterns = {"/report"},
    initParams = {
        @WebInitParam(name = "mood", value = "awake")})
    

    Both will result in one call of doFilter as you originally expected

    2016-01-16T11:28:53.485+0100|Info: TimeOfDay doFilter method before sending to chain
    
    2016-01-16T11:28:53.486+0100|Info: MoodServlet get method called
    
    2016-01-16T11:28:53.487+0100|Info: TimeOfDay doFilter method after sending to chain
    
    0 讨论(0)
  • 2021-02-19 17:04

    As Mohan has stated, @Component will make your filter be called twice if you have it already registered in you Application class, like this:

    resources.add(new MyFilter());
    

    If that's the case you have to choose between annotating it or registering it. But this is only valid for JAX-RS applications that use Spring. Not the topic of this question.

    0 讨论(0)
提交回复
热议问题