1

My servletfilter for logging page views is receiving a GET and a POST with a single page request. I tracked it back to using Omnifaces ViewScope on page backing bean.

@Named
@org.omnifaces.cdi.ViewScoped

I happen to notice double page views in my log file with exact timestamps. Debugging with the below simplified version, on a single page request, the doFilter is executed twice, first time is a GET and the URL is the URL I am browsing to. Then doFilter is executed again and it is a POST and the URL is the page I came from. If I page refresh I'll see a GET then a POST to the same page. If I use javax.faces.view.ViewScoped, only GET requests come in.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    System.out.println(new java.util.Date() + " " + ((HttpServletRequest) request).getMethod() + " " + httpRequest.getServletPath());
    chain.doFilter(request, response);
}

Example, if I am viewing http://localhost:8080/myApp/page1.xhtml and I change url to page2.xhtml

the filter will write out

Wed Aug 26 12:17:04 EDT 2020 GET /page2.xhtml
Wed Aug 26 12:17:04 EDT 2020 POST /page1.xhtml

Perhaps by design?. But I only want to log the page that the user is browsing to, not the one they came from. Is it as simple as?:

    if(((HttpServletRequest) request).getMethod().equalsIgnoreCase("GET")){
      //Write to actual log file
    }

or am I using omnifaces viewscope wrong?

jeff
  • 3,618
  • 9
  • 48
  • 101

1 Answers1

3

This is indeed by design. The POST on the previous page basically sends a signal that the page has been unloaded and thus the logic behind the @ViewScoped knows that it has to immediately destroy the JSF view state and the physical bean.

See also the documentation:

... this CDI view scope annotation will guarantee that the @PreDestroy annotated method is also invoked on browser unload. This trick is done by navigator.sendBeacon. For browsers not supporting navigator.sendBeacon, it will fallback to a synchronous XHR request.

When you want to detect them in your filters, then you can use ViewScopeManager#isUnloadRequest().

if (!ViewScopeManager.isUnloadRequest(request)) {
    // Write to actual log file.
}

chain.doFilter(request, response); // Ensure that this just continues!

This is admittedly indeed not clearly enough documented, I'll keep this in mind for the next release.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    Thanks! So then is Omnifaces ViewScope version more efficient with memory than javax version as it won't leave a bunch of abandoned view states on the server waiting to be destroyed by the server's inactivity timeout? – jeff Aug 27 '20 at 15:22
  • 1
    Exactly. See also https://stackoverflow.com/q/30410601 and https://stackoverflow.com/q/40569971 – BalusC Aug 27 '20 at 18:12