Mark W
Mark W

Reputation: 5964

Why does JSF hit xhtml page 3 times

I have a JSF application. Upon hitting an entry point.

/MyApp/start.xhtml 

The page contains a view action which will decide from the query string params which page to go to.

<f:viewAction action="#{startController.newQuote()}" />

.

@ManagedBean
@SessionScoped
public class StartController {
public String newQuote(){
    ....
    FacesContext fc = FacesContext.getCurrentInstance();
    ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler)fc.getApplication().getNavigationHandler();
    nav.performNavigation("aboutYou.xhtml?faces-redirect=true");
}

The aboutYou.xhtml is reportedly hit 3 times according to my filter.

@WebFilter("*.xhtml")
public class TrackingFilter implements Filter {

    private static Logger LOG = Logger.getLogger(TrackingFilter.class);

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

        HttpServletRequest req = (HttpServletRequest) request;

        LOG.trace("request URI: " + req.getRequestURI());
}

why is this? I suspect it is to do with the PRG pattern used by ?faces-redirect=true but I might expect to see this 2 times, not 3.

how do I optimise my filter so that I only catch a single action of moving to that page?

Upvotes: 2

Views: 292

Answers (1)

BalusC
BalusC

Reputation: 1108632

As per the comment:

The browser shows x2 HTTP200 POSTs

That's thus 1 GET request as fully expected. Those POST requests can happen if you're firing some ajax request on load of the requested page. E.g., assuming PrimeFaces, with <p:outputPanel deferred="true">, <p:remoteCommand autoRun="true">, etc. Usually all related to lazy loading.

You can in the filter recognize POST requests by inspecting HttpServletRequest#getMethod().

if ("POST".equals(request.getMethod())) {
    // It's a POST request.
}

Or, specifically JSF ajax requests by inspecting Faces-Request header.

if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
    // It's a JSF ajax request.
}

Unrelated to the concrete problem, you're not performing a PRG here at all. The <f:viewAction> is by default only invoked on a GET request, not on a POST request (it only does that when you add onPostback="true"). And, the <f:viewAction action> behaves exactly the same as <h:commandButton action>, including returning a navigation case outcome as usual (with the only difference that it's a GET, not a POST). So all that navigation handler and redirect mess is unnecessary.

public String newQuote() {
    // ...

    return "aboutYou.xhtml";
}

The navigation handler approach is only necessary if returning a String outcome is not supported (like in <f:event type="preRenderView">). The redirect is only necessary if the initial request is a POST request (like in <h:commandButton action> or <f:viewAction onPostback="true">).

Upvotes: 3

Related Questions