在过去,由于为了获得新数据而不得不重新加载web页面(或者加载其他页面)导致web应用程序发展被限制。虽然有其他方法可用(不加载其他页面),但是这些技术都没有被很好地支持而且有bug成灾的趋向。在过去的几个月里,一个过去并不被广泛支持的技术已经被越来越多的web冲浪者(web surfers??是指浏览器还是浏览者?)所接受,它给了开发者更多的自由开发先进的web应用程序。这些通过javascript来异步取得xml数据的应用程序,被亲切的称为“Ajax应用程序”(Asynchronous Javascript and XML applications)。在这篇文章中,我将会解释如何通过Ajax来取回一个远程的XML文件并更新一个web page,并且随着这个系列的继续,我将讨论更多的方法,使用ajax技术将你的web应用程序提升到一个新的层次。
然而,最大的威胁之一,来自日益复杂的使用AJAX的客户端脚本和服务器端脚本。这些脚本被技术手段隐藏在了视线之外,使测试很不直观;同时,这种新技术看起来也使web开发者忘掉了基本的好的编码方式。就像访问控制和输入校验这样的问题也不会消失,它们变得更多更复杂了。
5个最重要的AJAX安全提示:
为了取得成功,你必须从好的计划开始。必须集中你的才智减少和简化AJAX调用,创建一个标准的响应格式,在任何地方都要遵循这个协定(理想的XML)。
遵循来自像开放万维网应用安全计划那样的站点的最优方法。这里面特别包含了访问控制和输入校验漏洞检查,同时确保敏感信息使用over SSL胜过使用普通文本。
永远不要假设服务器端AJAX对于访问控制或者用户输入校验检查能够代替在服务器上的最终再检查。增加AJAX控制永远不会减少你的验证工作量,它们只能增加你的工作量。
永远不要假设客户端的混淆技术(obfuscation,在这里指使JavaScript难于阅读和解码)能够保护你非常重要的商业秘密。使用JavaScript是隐藏程序设计最没用的一种手段,还能够为你的对手提供好处。
最后,你必须非常好的领导你的开发团队。使用AJAX听起来非常引人注目,但是你应该认识到要保留你的开发团队以便开发版本2,当然现在你应该开发非常稳定的版本1。
应用举例1:web页面中级联菜单的设计
Easyjf-menu.jsp:
<@page contentType=”text/html;charser=UTF-8” language=”java”%>
……..
<!-- Script 代码开始 -->
var XMLHttpReq;
var currentSort;
//创建xmlhttprequset对象
function createXMLHttpRequest(){
if(window.XMLHttpRequest){
XMLHttpReq=new XMLHttpRequest();
}
else if (window.ActiveXObject){
try{
XMlHttpReq=new ActiveXObject(“Msxml2.XMLHTTP”);
}catch(e){}
try{
XMLHttpRequest=new ActiveXObject(“Microsoft.XMLHTTP”);
}catch(e){}
}
}
//发送请求函数
function sendRequest(url){
createXMLHttpRequest();
XMLHttpReq.open(“GET”,url,true);
XMLHttpReq.onreadystatechange=processResponse;
XMLHttpReq.send(null);
}
//处理返回信息函数
function processResponse(){
if(XMLHttpRequest.readyState==4){
if(XMLHttpRequest.status==200){
updateMenu();
}else{alert(“您请求的页面有异常!”)}
}
}
//更新菜单函数
function updateMenu(){
var res=XMLHttpReq.responseXML.getElementIdByTagName(“res”);
var sunMenu=””;
for(var i=0;i submenu=subMenu+res[1].fistChild.data+”
”;
}
currentSort.innerHTML=submenu;
}
//创建级联菜单
function showSubMenu(obj){
currentSort=document.getElementById(obj);
currentSort.parentNode.style.display=””;
sendRequest(“menu?sort=”+obj);
}
<!-- Script 代码结束 -->
EasyJF成员
大峡
本例中只要你选择成员分类名称就会自动显示成员名称:
首先在eclipse中建一个项目,名称你自己做主了,这里为Easyjf-menu,对应的浏览器页面代码为:
该页面中提供了对应的菜单以供用户选择,用户选择菜单后,调用showSubMenu(‘XXX’)函数,其中参数用于传递用户所选菜单的标识信息到服务器以决定获取服务器的哪个在菜单内容,首先获得菜单的识别信息,再提交给Ajax,这里用innerHTML属性实现定位显示!
应用举例2:自动保存草稿
相信用过Gmail的人都知道Gmail有一个草稿自动保存的功能,每过一段时间,Gmail都会自动保存邮件草稿,这样在一些突发情况下就能快速地恢复工作,免得写了半天的邮件眨眼之间就没有了。在学了AJAX之后,笔者也给自己的blog加上了这个功能。当然,这个应用并不只限于blog上,应该说还是比较通用的。
首先是表单填写页面,用一个ID为AutoSaveMsg的DIV来显示返回信息,并且用一个ID为Draft_AutoSave的CheckBox来确定是否进行自动保存,然后将Textarea的ID命名为message。同时为了应对多用户同时使用的需要,加上用户名,每个用户的草稿分开保存。为了说明方便,这里把一些修饰性的东西去掉,这样看起来比较明了。
AJAX应用之草稿自动保存<br />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- 用户名默认为NONAME -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
用户名:<input type="text" name="memName" id="memName" size="20" value="NONAME" />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- 在自动保存选项的onclick事件中调用自动保存状态设置函数 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<input onclick="SetAutoSave();" type="checkbox" id="Draft_AutoSave" value="1" checked="true" />自动保存?<br />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
内容:
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<textarea id="message"></textarea><br />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- AutoSaveMsg显示返回信息 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<div id="AutoSaveMsg"></div>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<input type="submit" value="提交内容" />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- 调用函数恢复最后保存的草稿 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<input type="button" onclick="AutoSaveRestore();" value="恢复最后保存的草稿" />
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
</div>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
</div>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- 将JS代码放在所有对象之后,以免在页面未加载完成时出现对象不存在的错误 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- AJAX类 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<script type="text/javascript" src="ajaxrequest.js"></script>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<!-- 自动保存代码 -->
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<script type="text/javascript" src="autosave.js"></script>
接下来是autosave.js
程序代码:
// 首先设置全局变量
// 要保存的内容对象FormContent
var FormContent=document.getElementById("´message"´);
// 显示返回信息的对象
var AutoSaveMsg=document.getElementById("´AutoSaveMsg"´);
// 用户名
var memName=document.getElementById("´memName"´).value;
// 自动保存时间间隔
var AutoSaveTime=60000;
// 计时器对象
var AutoSaveTimer;
// 首先设置一次自动保存状态
SetAutoSave();
// 自动保存函数
function AutoSave() {
// 如果内容或用户名为空,则不进行处理,直接返回
if(!FormContent.value||!memName) return;
// 创建AJAXRequest对象,详细使用见文章开始的链接
var ajaxobj=new AJAXRequest;
ajaxobj.url="´autosave.asp"´
ajaxobj.content="´memname="´+escape(memName)+"´&postcontent="´+escape(FormContent.value);
ajaxobj.callback=function(xmlObj) {
// 显示反馈信息
AutoSaveMsg.innerHTML=xmlObj.responseText;
}
ajaxobj.send();
}
// 设置自动保存状态函数
function SetAutoSave() {
// 是否自动保存?
if(document.getElementById("´Draft_AutoSave"´).checked==true)
// 是,设置计时器
AutoSaveTimer=setInterval("´AutoSave()"´,AutoSaveTime);
else
// 否,清除计时器
clearInterval(AutoSaveTimer);
}
// 恢复最后保存的草稿
function AutoSaveRestore() {
// 创建AJAXRequest对象
var ajaxobj=new AJAXRequest;
// 提示用户正在恢复
AutoSaveMsg.innerHTML="´正在恢复,请稍候……"´
ajaxobj.url="´autosave.asp"´
ajaxobj.content="´action=restore&memname="´+escape(memName);
ajaxobj.callback=function(xmlObj) {
// 提示用户恢复成功
AutoSaveMsg.innerHTML="´恢复最后保存成功"´
// 如果内容为空则不改写textarea的内容
if(xmlObj.responseText!="´"´) {
// 恢复草稿
FormContent.value=xmlObj.responseText;
}
}
ajaxobj.send()
}
最后是autosave.asp,用于在后台保存草稿:
程序代码:
<%@LANGUAGE="VBscript" CODEPAGE="65001"%>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<% Option Explicit %>
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
<%
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 语言为VBScript,编码为UTF-8,要求变量声明
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 出现错误则忽略,继续执行
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
On Error Resume Next
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
(联动北方技术论坛 - Powered by Landingbj) [网际游航]' 定义一些变量
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Dim PostContent,memName,action,objStream
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
(联动北方技术论坛 - Powered by Landingbj) [网际游航]' 获取操作,是保存草稿还是恢复草稿
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
action=Request.Form("action")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 获取用户名
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
memName=Request.Form("memname")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 获取草稿内容
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
PostContent=Request.Form("postcontent")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
IF action="restore" Then
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 恢复草稿,如果用户名不为空则进行恢复操作
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
IF memName<>Empty Then
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 使用 ADODB.Stream 来进行文件操作
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Set objStream = Server.CreateObject("ADODB.Stream")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
With objStream
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Type = 2
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Mode = 3
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Open
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 文件名为 autosave_ + 用户名 + .txt
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.LoadFromFile(Server.MapPath("autosave_"&memName&".txt"))
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Charset = "utf-8"
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
'.Position = 0
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
PostContent = .ReadText()
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Close
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End With
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Set objStream = NoThing
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 输出草稿
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
IF PostContent<>"" Then Response.Write(PostContent)
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End IF
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Else
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 保存草稿,如果草稿内容和用户名均不为空则进行保存操作
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
IF PostContent<>Empty AND memName<>Empty Then
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 使用 ADODB.Stream 来进行文件操作
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Set objStream = Server.CreateObject("ADODB.Stream")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
With objStream
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Type = 2
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Mode = 3
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Open
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Charset = "utf-8"
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Position = objStream.Size
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.WriteText= PostContent
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.SaveToFile Server.MapPath("autosave_"&memName&".txt"),2
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
.Close
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End With
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Set objStream = NoThing
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
' 输出保存是否成功信息
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
If Err.Number=0 then
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Response.Write("最后于 "&Now()&" 自动保存成功")
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Else
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
Response.Write("最后于 "&Now()&" 自动保存失败,错误号:"&Err.Number&",错误描述:"&Err.Dscription)
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End If
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End IF
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
End IF
(联动北方技术论坛 - Powered by Landingbj) [网际游航]
%>
(联动北方技术论坛 - Powered by Landingbj) [ 网际游航]
<%@LANGUAGE="´VBscript"´ CODEPAGE="´65001"´%>
至此,AJAX草稿自动保存完成了。
该贴由koei转至本版2014-5-2 16:25:35