Search code examples
ajaxjsf-2primefaceserror-handlingomnifaces

FullAjaxExceptionHandler does not redirect to error page for Ajax request


I know there has been numerous questions here on this question, but almost all of them suggest adding the following code because there is another layer "above" the FullAjaxExceptionHandler that is sending a plain redirect instead of doing an Ajax redirect (see this similar question):

if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
// JSF ajax request. Return special XML response which instructs JavaScript that it should in turn perform a redirect.
response.setContentType("text/xml");
response.getWriter()
    .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
    .printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", loginURL);
} else {
    // Normal request. Perform redirect as usual.
    response.sendRedirect(loginURL);
}

My question is that I'm simply configuring Omnifaces's FullAjaxExceptionHandler to do all the error handling, I do not have Spring Security or container managed security that is intercepting the request before FullAjaxExceptionHandler can do it's thing. I can breakpoint into FullAjaxExceptionHandler and see that when the following lines of code is executed, my error page is still not being redirected.

String viewId = Faces.normalizeViewId(errorPageLocation);
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, viewId);
context.setViewRoot(viewRoot);
context.getPartialViewContext().setRenderAll(true);
        ...
    context.renderResponse();

Instead, the Ajax request where the exception originated has this in it's response body:

<?xml version='1.0' encoding='UTF-8'?>
    <partial-response>
        <changes>
            <update id="javax.faces.ViewRoot"><![CDATA[<html xmlns="http://www.w3.org/1999/xhtml">... html of error page here ... </html>]]></update>
            <update id="javax.faces.ViewState"><![CDATA[-3527653129719750158:5595502883804776498]]></update>
        </changes>
    </partial-response>

It looks like FullAjaxExceptionHandler isn't doing what it's supposed to do, or am I missing something?

Update

Attaching browser JS output console screen cap.JS output console

Problem Identified

Turns out that the HTML of my error page is malformed, it contains the following snippet, which results in the mismatched tag error in the browser:

<script type="text/javascript">
//<![CDATA[
scrollTo(0, 0);
//]]>
</script>

This seemed to have closed the CDATA tag prematurely. This HTML was a result of the <h:outputScript/> tag, which I removed since I don't really need it.


Solution

  • The ajax response looks completely fine, it's having an <update id="javax.faces.ViewRoot"> containing the whole error page document, so the FullAjaxExceptionHandler did its job properly.

    Your concrete problem is more likely caused in the client side or even in the error page document itself, after the ajax response has been retrieved. It's then JavaScript's turn to parse that ajax response and replace the current HTML document accordingly. Checking the browser's JavaScript console should give any clues as to problems during that step. In your particular case, the problem seems to be caused by a nested CDATA block around the content rendered by <h:outputScript> which in turn caused a JavaScript parsing error.

    Unfortunately, I can't reproduce the problem with any Mojarra version I've at hands. Perhaps you've somewhere a custom/3rd party script renderer who's responsible for adding that CDATA block. That script renderer should skip the CDATA block when PartialViewContext#isAjaxRequest() returns true. If you still can't figure it out, then your best bet is to replace the <h:outputScript> by a plain HTML <script> or even to remove it altogether — as you ultimately did.