我有一个登录页面:
<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>
使用此操作方法:
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);
}
}
提交此表单有时会导致JS错误:
httpError:Http Transport返回0状态代码。这通常是混合ajax和完整请求的结果。出于性能和数据完整性的原因,这通常是不受欢迎的。
我不明白我做错了什么。这是怎么造成的,我该如何解决?
答案 0 :(得分:5)
如果其中一个输入字段在更改时仍然处于焦点状态并且通过鼠标或[enter]键按下提交按钮而不是标记为(以便输入字段的更改事件首先触发),则确实存在该特定错误的机会)。在两个ajax请求之间将发生竞争条件:由输入字段的更改事件触发的请求和由提交按钮的操作事件触发的另一个请求。在这种情况下,未确定哪一个会首先命中服务器。
在JSF中,ajax请求是queued。因此,如果一个命中服务器,另一个将等到它返回并完成。当提交按钮的ajax请求是第一个命中服务器的请求时,将发生您的问题。如果登录成功,服务器将返回执行重定向的指令。在完成ajax请求期间,此重定向由JavaScript处理。在此之后,队列中的下一个ajax请求(如果有的话)将被触发(尽管重定向!这反过来IMO在JSF的ajax引擎中出现设计错误,但除此之外)。但是,由于文档已通过重定向更改,因此第二个ajax请求未命中,导致此错误。
总而言之,这种ajax形式的方法有点奇怪。输入字段和提交按钮分别通过ajax而不是通过提交按钮一次性发送它们的值。它看起来非常像您最初在提交按钮中有<f:ajax>
,但您认为未处理输入值,因此您决定在这些输入字段中添加另一个<f:ajax>
。
这不是完全正确的方法。您应该在提交按钮中使用execute="@form"
,以指示它执行(处理)整个表单。
因此,所以:
<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>
这样一次只能触发一个ajax请求,消除了竞争条件的风险。
答案 1 :(得分:4)
最后我发现了真正的问题。
验证之后,在重定向之前,我在会话中添加了一些变量。 但我正在列出一个对象列表,这需要很长时间才能完成。
可能jsf仍在等待返回执行ajax请求,在完成之前我刷新了页面,导致错误。
我删除了它,现在一切都很好^^
非常感谢@BalusC和@bhdrk向我展示了正确的使用方法。
答案 2 :(得分:3)
只需添加execute =&#34; @ form&#34;到&lt; f:ajax /&gt;它应该工作。
<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>