Question

I have a login page:

<h:form id="f_login" >
    <f:passThroughAttribute name="data-ajax" value="false" />

    <h:messages id="message" showDetail="false" errorClass="error_msg" fatalClass="success_msg" infoClass="info_msg" warnClass="warning_msg" />

    <h:inputText value="#{loginWEB.user.email}" >
        <f:passThroughAttribute name="placeholder" value="Email" />
        <f:ajax event="change" execute="@this" />
    </h:inputText>

    <h:inputSecret value="#{loginWEB.user.senha}" autocomplete="off" >
        <f:passThroughAttribute name="placeholder" value="Senha" />
        <f:ajax event="change" execute="@this" />
    </h:inputSecret>

    <h:commandButton id="btn_login" value="Login" action="#{loginWEB.login()}" >
        <f:passThroughAttribute name="data-theme" value="g" />
        <f:ajax render="message" />
    </h:commandButton>
</h:form>

With this action method:

public void login() {
    try {

        FacesContext context = FacesContext.getCurrentInstance();

        if (...) { //Verify email and password
            context.getExternalContext().redirect("/templates/main.xhtml"); 
        }
        else {
            FacesMessage message = new FacesMessage("Invalid email or password");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            context.addMessage(null, message);
        }

    } catch (Exception e) {
        Logger.getLogger(LoginWEB.class.getName()).log(Level.SEVERE, null, e);
    }
}

Submitting this form sometimes causes a JS error:

httpError: The Http Transport returned a 0 status code. This is usually the result of mixing ajax and full requests. This is usually undesired, for both performance and data integrity reasons.

I don't understand what I'm doing wrong. How is this caused and how can I solve it?

Was it helpful?

Solution 2

Finally I found the real problem.

After the verification, and before the redirect, I put some variables in my session. But I was putting a list of object, and it was taking long time to do it.

Probably the jsf was still waiting by the return to do the ajax request and before finish it I was refreshing the page, causing the error.

I removed it, and now everything is fine again ^^

Thank you so much to @BalusC and @bhdrk for show me the right approach to use.

OTHER TIPS

There's indeed chance on that specific error if one of the input fields has still focus while it's changed and the submit button is pressed by mouse or [enter] key instead of being tabbed to (so that the input field's change event triggers first). A race condition will occur between 2 ajax requests: the one triggered by input field's change event and the other triggered by submit button's action event. It's in this kind of situation undetermined which one would hit the server first.

In JSF, ajax requests are queued. So, if one hits the server, the other will wait until it returns and completes. Your problem will occur when the ajax request of the submit button is the first one which hits the server. In case of a successful login, the server will return an instruction to perform a redirect. This redirect is handled by JavaScript during the complete of the ajax request. After this, the next ajax request in the queue, if any, will be fired (in spite of the redirect! which is in turn IMO a design error in JSF's ajax engine, but that aside). However, since the document has changed by a redirect, the second ajax request misses hit, causing this error.

All in all, this ajax form approach is somewhat strange. The input fields and submit button are each individually sending their value by ajax instead of all at once via the submit button. It looks very much like that you initially had that <f:ajax> in the submit button, but you figured that the input values weren't processed, so you decided to add another <f:ajax> to those input fields.

This is not entirely the right approach. You should be using execute="@form" in the submit button in order to instruct it to execute (process) the entire form.

Thus, so:

<h:form id="f_login">
    <f:passThroughAttribute name="data-ajax" value="false" />

    <h:messages id="message" showDetail="false" errorClass="error_msg" fatalClass="success_msg" infoClass="info_msg" warnClass="warning_msg" />

    <h:inputText value="#{loginWEB.user.email}">
        <f:passThroughAttribute name="placeholder" value="Email" />
    </h:inputText>

    <h:inputSecret value="#{loginWEB.user.senha}" autocomplete="off">
        <f:passThroughAttribute name="placeholder" value="Senha" />
    </h:inputSecret>

    <h:commandButton id="btn_login" value="Login" action="#{loginWEB.login}">
        <f:passThroughAttribute name="data-theme" value="g" />
        <f:ajax execute="@form" render="message" />
    </h:commandButton>
</h:form>

This way only one ajax request will be fired at once, eliminating the risk for race conditions.

just add execute="@form" to <f:ajax/> it should work.

<h:commandButton id="btn_login" value="Login" action="#{loginWEB.login()}" >
    <f:passThroughAttribute name="data-theme" value="g" />
    <f:ajax execute="@form" render="message" />
</h:commandButton>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top