用 Ajax 提交表单数据
本节将展示如何使用 Ajax 向 JSF 页面发送表单数据,还会涵盖与之相关的其他一些主题,例如错误处理以及 XMLHttpRequest 对象的正确管理,这些都是防止 Web 浏览器内的内存泄漏所必须了解的。
创建和发送 Ajax 请求
submitFormData() 函数的代码可以在 AutoSaveScript.js 文件中找到(请参见 下载 部分),该函数使用 Ajax 请求对象向 Web 服务器提交编码后的数据。首先,它需要创建这个请求对象,如果是 Microsoft® Internet Explorer,就使用 ActiveXObject(),如果是支持 Ajax 的其他浏览器,比如 Firefox、Netscape、Mozilla、Opera 和 Safari,就使用 XMLHttpRequest()。清单 5 显示了创建 XMLHttpRequest 对象所需的代码。
清单 5. 创建 Ajax 请求对象
var xhr;
if (window.ActiveXObject)
xhr = new ActiveXObject("Microsoft.XMLHTTP");
else if (window.XMLHttpRequest)
xhr = new XMLHttpRequest();
else
return null;
...
}
编码后的表单数据被提交给由表单的 action URL 所识别的页面,使用的是特定的 HTTP method,在 JSF 表单的情况下,此方法即为 POST。submitFormData() 函数也可以同非 JSF 表单一起使用,这类表单有可能会使用默认的 GET 方法或 POST。即使这个表单没有指定 action URL,此代码仍可以工作。在这种情况下,submitFormData() 将会使用由 document.URL 获得的当前页面的 URL。编码后的表单数据可通过 getFormData() 函数从 form 对象检索到,该函数在前面已介绍过。如果此 HTTP 方法是 GET,那么编码后的数据会追加到 URL ? 字符后面。之后,submitFormData() 通过 open() 方法初始化 xhr 对象(见清单 6)。
清单 6. 初始化 Ajax 请求对象
...
var method = form.method ? form.method.toUpperCase() : "GET";
var action = form.action ? form.action : document.URL;
var data = getFormData(form);
var url = action;
if (data && method == "GET")
url += "?" + data;
xhr.open(method, url, true);
...
}
当从服务器收到对 Ajax 请求的响应时,会调用称为 submitCallback() 的内部函数。如果 autoSaveDebug 的值为 true,这个 Ajax 回调就会发出错误信号,请求虽完成(readyState 为 4),但其状态却不对(status 不是 200)。一旦发生错误,系统就会通过 alert() 报告 xhr 对象的 status 和 statusText 属性,而且 autoSaveDebug 标记也会设为 false 以防您一次又一次地收到错误消息(因为表单保存是周期性执行的)。如果重新加载此页面,JavaScript 代码就会重新初始化,若导致 HTTP 错误的问题仍没有得到解决,您将会再次看到错误消息。这个功能非常适合开发阶段的调试之用。在实际的生产环境中,当发生错误时,与显示告警信息相比,最好是将用户重新引导到其他页面。不管何种情况,xhr 对象的 onreadystatechange 属性都必须包含一个对 submitCallback() 的引用以便此回调函数在 Ajax 请求的生命周期中能被调用(见清单 7)。
清单 7. 回调函数
function submitFormData(form) {
...
function submitCallback() {
if (autoSaveDebug && xhr.readyState == 4
&& xhr.status != 200) {
autoSaveDebug = false;
alert("Auto-Save Error: "
+ xhr.status + " " + xhr.statusText);
}
}
xhr.onreadystatechange = submitCallback;
...
}
接下来,submitFormData() 设定 Ajax-Request 报头,它对示例应用程序是特定的,用来在服务器端识别 Ajax 请求,这将在本文后面的部分进行介绍。如果 HTTP 方法是 POST,那么 submitFormData() 函数会设置标准 Content-Type 报头并且会使用 xhr 对象的 send() 方法将表单数据提交给 JSF 页面。如果 HTTP 方法是 GET(当前未被 JSF 表单使用),那么表单数据应该已经追加到此 URL,并会用 null 参数调用 send()。在提交表单数据后,此函数返回一个对 xhr 对象的引用(见清单 8)。
清单 8. 发送 Ajax 请求
...
xhr.setRequestHeader("Ajax-Request", "Auto-Save");
if (method == "POST") {
xhr.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xhr.send(data);
} else
xhr.send(null);
return xhr;
}