一、安全性问题
1.1 同源策略
JavaScript不能访问不同来iuande脚本或者文档。这是浏览器厂商采取的一个安全措施。否则,恶意代码的编写者就能在任何地方执行代码。同源策略提出,仅当两个页面的协议(HTTP),端口号(默认为80)和主机名相同时,它们才是同源的。
考虑以下两个页面:
- 页面1位于:http://www.site.com/folder/mypage1.html
- 页面2位于:http://www.site.com/folder/mypage2.html
根据同源策略,这是两个同源页面。它们有相同的主机(www.site.com),使用相同的协议(HTTP),并在相同的端口上访问(这两个页面都没有指定端口,因此都使用80端口)。由于这是两个同源页面,因此一个页面中的JavaScript可以访问另一个页面
再考虑下面的两个页面
- 页面1位于:http://www.site.com/folder/mypage1.html
- 页面2位于:https://www.site.com/folder/mypage2.html
这两个页面是不同源的。他们的主机名相同,但协议和端口号不同。页面1使用HTTP协议(端口号为80),而页面2使用HTTPS协议(端口号为443)。这一差异虽然小,但足以使这两个页面不同源。因此,其中一个页面的JavaScripte无法访问另一页面。
这与Ajax技术有什么关系?因为JavaScript在Ajax中占很大比例。例如,由于同源策略的限制,XMLHttpRequest对象将无法访问任何不同来源的的文件或文档。这一问题很容易解决uefa:使用一个同源的页面作为代理(proxy),获取另一个非同源服务器上的数据。同源策略还影响到隐藏的frame/iframe技术,即使两个不同来源的页面位于同一个框架中,JavaScript也无法与这两个页面交互。
1.2 ActiveX
XMLHttpRequest的一个弊端在于它是一个ActiveX控件,只适用于Windows上的IE。如果用户完全禁用ActiveX,或者站点被标记为某个安全区域,就无法创建ActiveX对象,使基于XMLHttpRequest的Ajax应用程序无法正常工作
二、可用性问题
2.1 浏览器的Back按钮
XMLHttpRequest的一个优点是易于使用。我们只需创建对象,发送请求,等待服务器的响应。但是,这个对象有一个缺点:大多数浏览器都不能在其历史记录中保存使用该对象发出的请求,因此,XMLHttpRequest实际上使用浏览器的Back按钮失效。这是一些支持Ajax的应用程序或组件希望出现的副作用,但它可能改用户带来严重的可用性问题
2.2 使用iframe创建支持Back和Forward按钮的表单
使用旧式的Ajax技术可以避免使浏览器的导航按钮失效,即使用隐藏框架/内置框架进行客户端和服务端的通信。只有使用这两个框架时,这种方法才能正常功能做。其中一个框架是隐藏的,另一个框架是可见的。
隐藏可见技术包含4个步骤
- 用户启动对隐藏框架的Javascript调用。为此,用户可以单击可见框架中的按钮,或者执行其他形式的交互操作。这个调用通常只是将隐藏框架重定向到另一个网页上。这个重定向会自动触发第二步。
- 向服务器发送请求,服务器会处理数据
- 服务器响应(一个网页)发送回隐藏框架
- 浏览器再隐藏框架中加载网页,执行联系课件框架所需的Javascript代码
2.3 服务器响应
使用XMLHttpRequest对象从服务器上获取数据时,服务器的响应仅包含很少几个词语,当下面案例的响应不同,它必须包含两项内容:
- 数据,必须是HTML格式
- iframe接收到HTML响应时联系父文档的机制
下面的的代码是响应HTML页面的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
top.checkUsername_callBack("available","some_userame");
</script>
</body>
</html>
2.4 iframe智能表单
(1)数据提交页面:validate_iframe_form.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Form Field Validation</title>
<style type="text/css">
.fieldname
{
text-align: right;
}
.submit
{
text-align: right;
}
#hiddenFrame {
display: none;
}
</style>
<script type="text/javascript">
function checkUsername()
{
var userValue = document.getElementById("username").value;
if (userValue == "")
{
alert("Please enter a user name to check!");
return;
}
var url = "iframe_formvalidator.php?username=" + userValue;
frames["hiddenFrame"].location = url;
}
function checkUsername_callBack(data, userValue)
{
if (data == "available")
{
alert("The username " + userValue + " is available!");
}
else
{
alert("We're sorry, but " + userValue + " is not available.");
}
}
function checkEmail()
{
var emailValue = document.getElementById("email").value;
if (emailValue == "")
{
alert("Please enter an email address to check!");
return;
}
var url = "iframe_formvalidator.php?email=" + emailValue;
frames["hiddenFrame"].location = url;
}
function checkEmail_callBack(data, emailValue)
{
if (data == "available")
{
alert("The email " + emailValue + " is currently not in use!");
}
else
{
alert("We're sorry, but " + emailValue + " is in use by another user.");
}
}
</script>
</head>
<body>
<form>
<table>
<tr>
<td class="fieldname">
Username:
</td>
<td>
<input type="text" id="username" />
</td>
<td>
<a href="javascript: checkUsername()">Check Availability</a>
</td>
</tr>
<tr>
<td class="fieldname">
Email:
</td>
<td>
<input type="text" id="email" />
</td>
<td>
<a href="javascript: checkEmail()">Check Availability</a>
</td>
</tr>
<tr>
<td class="fieldname">
Password:
</td>
<td>
<input type="text" id="password" />
</td>
<td />
</tr>
<tr>
<td class="fieldname">
Verify Password:
</td>
<td>
<input type="text" id="password2" />
</td>
<td />
</tr>
<tr>
<td colspan="2" class="submit">
<input type="submit" value="Submit" />
</td>
<td />
</tr>
</table>
</form>
<iframe src="about:blank" id="hiddenFrame" name="hiddenFrame" />
</body>
</html>
(2)后台处理页面:iframe_formvalidator.php
<html>
<head>
<title>Returned Data</title>
</head>
<body>
<?php
$array = Array(
Array("jmcpeak", "someone@zyx.com"),
Array("pwilton", "someone@xyz.com")
);
if (isset( $_GET["username"]) || isset( $_GET["email"]))
{
$result = false;
$jsFunction = "";
$searchTerm = "";
if (isset( $_GET["username"]))
{
$searchTerm = $_GET["username"];
$jsFunction = "checkUsername_callBack";
for ($i = 0; $i < count($array); $i++)
{
if (strtolower($array[$i][0]) == strtolower($searchTerm))
{
$result = true;
}
}
}
if (isset( $_GET["email"]))
{
$searchTerm = $_GET["email"];
$jsFunction = "checkEmail_callBack";
for ($i = 0; $i < count($array); $i++)
{
if (strtolower($array[$i][1]) == strtolower($searchTerm))
{
$result = true;
}
}
}
$strResult = ($result)?"not available":"available";
?>
<script>
top.<?php echo $jsFunction; ?>("<?php echo $strResult; ?>", "<?php echo $searchTerm; ?>" );
</script>
<?php
}
else
{
echo "PHP is working correctly. Congratulations!";
}
?>
</body>
</html>
(3)输入用户名和email地址点击”Check Availability”进行检查。提交后,文本框被清空,单击浏览器的Back按钮几次,前面输入的信息将按倒序出现。也可以单击Forward按钮进行测试
(4)代码解析
页面正文中的HTML没有变化,只是在最后添加了iframe标签。
<iframe src="about:blank" id="hiddenFrame" name="hiddenFrame" />
该框架初始化为欸一个空白的HTML页面,其name和id属性都包含hiddenFrame的值。后面使用name属性的值。从Bom的frames集合中获取这个框架。接下来设置该框架的CSS
#hiddenFrame {
display: none;
}
下面是Javascript代码
function checkUsername()
{
var userValue = document.getElementById("username").value;
if (userValue == "")
{
alert("Please enter a user name to check!");
return;
}
var url = "iframe_formvalidator.php?username=" + userValue;
frames["hiddenFrame"].location = url;
}
checkUsername()使用iframe替代XMLHttpRequest,来发出请求。改函数最后使用frames集合和location属性把URL加载到隐藏的iframe中。
剩余的函数不再赘述。
2.5 处理延迟
Web浏览器与传统的应用程序一样,其用户界面(UI)会提示浏览器执行某个任务。用户单击链接时,会运行一个跳动的动画,光标的旁边会出现一个沙漏图标,状态栏会显示浏览器加载页面的进度
这正是Ajax技术特别是XMLHttpRequest没有解决的另一个问题。但这个问题非常容易解决:只需添加UI元素,告诉用户某个任务正在运行,在该任务完成时删除或隐藏UI元素
2.6 在Ajax失败时正常退出
在理想情况下,编写的代码每次都能正常运行。但如果用户在浏览器上关闭了Javascript,Ajax就会运行失败
解决方法:创建一个旧式的网页,使用旧式的表单、链接和其他HTML元素。然后,关闭这些HTML元素的默认行为,并使用Javascript来添加相应的Ajax功能。考虑下面的超链接
<a href="http://www.baidu.com" title="test" onclick="return false;"></a>
这个功能的关键在于上述代码中的onclick事件处理程序,并返回false。可以在该事件处理程序中执行任何代码,只是最后必须放回false。这将告诉浏览器,单击超链接时不执行其默认动作。如果用户禁止了JavaScript,则忽略onclick事件处理程序,超链接将恢复其正常行为。
作为一个经验法则,应先创建网页,再添加Ajax.