代码改变世界

javascript进阶——Ajax

2014-02-25 00:08  OshynSong  阅读(490)  评论(0编辑  收藏  举报

统的Web 页面和应用中,用户每点击页面上的某个部分,浏览器就会向服务器发出一个请求,等待服务器做出响应,然后返回一个完整新网页,但在大多数情况下用户不得不忍受页面闪烁和长时间的等待。随着Web技术的发展和用户体验要求的提高,异步编程是提高用户体验,同时仅仅修改页面中需要修改的部分而大量减少网络流量,增加了实时性。这种异步编程的出现就是以Jesse James Garrett提出的Ajax这一名词得到最广泛的应用。Ajax是异步javascript与XML的缩写,就是对创建异步Web动态应用的一个统称。

一、基础回顾

1、HTTP请求

 

  • 建立连接:IE6及以前版本使用ActiveXObject创建,IE7以后及其他浏览器都支持XMLHttpRequest对象创建。
  • 请求类型:传递给XMLHttpRequest对象的open方法的第一个参数来确定,GET或POST。其中GET将数据放在open方法的第二个参数URL后面,只能发送字符串数据,而且大小也有限制。但是POST则是可以发送任意类型数据,大小也无限制(服务器端会规定上限),同时可以使用MIME类型规定发送数据类型,如application/x-www-form-urlencoded、text/xml、application/xml、application/json等。
[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. <pre code_snippet_id="203158" snippet_file_name="blog_20140225_1_8025697" name="code" class="javascript">function ajax(options){  
  2.     if (typeof XMLHttpRequest == "undefined"){  
  3.         XMLHttpRequest = function(){  
  4.              return new ActiveXObject(navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP");  
  5.         };  
  6.     }  
  7.     var xml = new XMLHttpRequest();  
  8.     options = {  
  9.         type: options.type || "GET",  
  10.         url: options.url || "",  
  11.         timeout: options.timeout || 5000,  
  12.         onComplete: options.onComplete || function(){},  
  13.         onError: options.onError || function(){},  
  14.         onSuccess: options.onSuccess || function(){},  
  15.         data: options.data || ""  
  16.     };  
  17.     xml.open(options.type, options.url, true); //最后一个参数为true是异步请求  
  18.     ...  
  19.   
  20. }</pre>  
  21. <pre></pre>  
  • 发送数据:发送的数据首先就需要整理格式以便于服务器端易于读取,称为串行化。不管是键值对的json对象还是一组表单值的多个数据,最终就是要串行化为字符串。
[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. fucntion serialize(a){  
  2.     var s =[];  
  3.     if (a.constructor == Array){  
  4.         for(var i = 0; i < a.length; i++){  
  5.             s.push(a[i].name + "=" +encodeURIComponent(a[i].value));  
  6.         }  
  7.     }else{  
  8.         for (var j in a){  
  9.             s.push(j + "=" + encodeURIComponent(a[j]));  
  10.         }  
  11.     }  
  12.     return s.join("&");  
  13. }  


 

2、HTTP响应

创建和使用XMLHtttpRequest比其他单向通信的优越之处在于能够从服务器读取不同形式的文本数据,包括其基石之一XML。xhr对象的两个属性包含对应格式的数据:responseXML和responseText。(服务器返回的是XML文档时responseXML存储的就是DOM文档,其他所有响应结果都放在responseText中)。在进行请求后到获取返回数据的这个过程中,有以下两个问题需要关注:处理错误和检查超时。

xhr的整个状态过程如下:

 

属性描述
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState

存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

  • 0: 请求未初始化
  • 1: 服务器连接已建立
  • 2: 请求已接收
  • 3: 请求处理中
  • 4: 请求已完成,且响应已就绪
status

200: "OK"

404: 未找到页面

对status的检查以及XMLHttpRequest状态的检查是确保得到正确结果的重要一步。特别是服务器返回的是HTML错误页面而非XML文档的时候。

 

另一个为了避免由于网络或其他未知原因导致无法及时得到响应时,应该人为设置一个合理的超时时间,超过后自动放弃请求。

3、处理返回数据

通过getResponseHeader函数可以获取返回数据的content-type首部,responseText和responseXML得到相应类型的数据。

 

[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. futncion httpData(xhr, type){  
  2.    var ct = xhr.getReponseHeader("content-type");  
  3.    var data = !type && ct && ct.indexOf("xml") >= 0;  
  4.    data = type == "xml" ? xhr.responseXML : xhr.responseText;  
  5.    if (type == "script"){  
  6.         eval.call(window, data);  
  7.    }  
  8.    return data;  
  9. }  

 

二、Ajax框架使用

1、jQuery

jQuery封装好了ajax调用,而且有良好的浏览器兼容性。其中$.ajax全局方法是其底层封装,然后以此继续封装了几个高层的方法:

 

  • $.get:封装好的以GET方法发送请求,参数(url,data,callback,datatype)
  • $.post:封装好的以POST方法发送请求,参数与get相同
  • $.getJSON:以GET方式发送请求,直接返回JSON格式的数据,不用传递返回数据类型的参数
  • $.getScript:以GET方式发送请求,直接返回Script格式的文本,不用传递返回数据类型的参数
同时还封装好了ajax所有的事件,已经序列化数据的函数serialize和serializearray。整体使用非常便捷。

2、Dojo

 Dojo 以 XmlHttpRequest 对象为基础,提供了一组静态函数来支持这些 HTTP 请求。其中特别提供了并发处理ajax请求的解决方案:
[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. dojo.require("dojo.DeferredList");   
  2. dojo.require("dojox.lang.async");   
  3. function getSoftMusic() {   
  4.    return dojo.xhrGet({   
  5.        url: "/music/softMusic",   
  6.        handleAs: "json"  
  7.    });   
  8. }   
  9. function getFolkMusic() {   
  10.    return dojo.xhrGet({   
  11.        url: "/music/folkMusic",   
  12.        handleAs: "json"  
  13.    });   
  14. }   
  15. function getCountryMusic() {   
  16.    return dojo.xhrGet({   
  17.        url: "/music/countryMusic",   
  18.        handleAs: "json"  
  19.    });   
  20. }   
  21. // 利用 dojo.DeferredList 处理并发的 Ajax 请求  
  22. var d1 =  getSoftMusic(), d2 =  getFolkMusic(), d3 =  getCountryMusic(),   
  23. defList = new dojo.DeferredList([d1, d2, d3]);   
  24. defList.then(function(results) {   
  25.    dojo.forEach(results, function(result) {   
  26.        console.log(result[1]);   
  27.    });   
  28. });   
  29. // 利用 dojox.lang.async.par 处理并发的 Ajax 请求  
  30. var arrayOfAjax = [getSoftMusic, getFolkMusic, getCountryMusic];   
  31. dojox.lang.async.par(arrayOfAjax)().then(function(results) {   
  32.    dojo.forEach(results, function(result) {   
  33.        console.log(result);   
  34.    });   
  35. });  
相比之下,用 DeferredList 更为灵活。DeferredList 在默认情况下,会完成所有的 Ajax 请求,即使某一个 Ajax 请求失败了,最后 DeferredList 仍能够触发"resolved"状态的回调函数,并将相应的信息置于回调函数的参数中。而 dojox.lang.async.par 只会在所有的 Ajax 请求成功返回之后才会将各个 Ajax 请求的返回的信息传递给回调函数。当某一个 Ajax 请求失败了,dojox.lang.async.par 会将排在这个请求之后的所有 Ajax 请求取消。并触发"rejected"状态的回调函数。
串行ajax:
[javascript] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. dojo.require("dojox.lang.async");   
  2.  function deleteSoftMusic() {   
  3.     return dojo.xhrDelete({   
  4.        url: "/music/softMusic",   
  5.         handle: function(response) {   
  6.             console.log(response);    
  7.         }   
  8.    });   
  9.  }   
  10.  function deleteFolkMusic() {   
  11.     return dojo.xhrDelete({   
  12.        url: "/music/folkMusic",   
  13.         handle: function(response) {   
  14.             console.log(response);    
  15.         }   
  16.    });   
  17.  }   
  18.  function deleteCountryMusic() {   
  19.     return dojo.xhrDelete({   
  20.        url: "/music/countryMusic",   
  21.         handle: function(response) {   
  22.             console.log(response);    
  23.         }   
  24.    });   
  25.  }   
  26. var arrayOfAjax = [deleteSoftMusic, deleteFolkMusic, getCountryMusic];   
  27. dojox.lang.async.seq(arrayOfAjax)().allBoth(function(result) {   
  28.     console.log(result);   
  29.  });  

 

三、关注漏洞

Ajax 吸引 Web 开发人员的地方也是对其安全性最易受威胁的地方。众多安全专家一致认为 Web 应用程序是网络犯罪的一大目标,但是 Web 安全通常只是企业安全预算的一小部分。由于 Ajax 被用于开发很多可在 Web 上看到的应用程序,因此它的流行使其成为攻击者在 JavaScript 代码中寻找漏洞的目标。

 

1、基于浏览器的攻击

 

JavaScript 是 Ajax 的基础,恶意代码经常使用它。要让一个基于浏览器的攻击生效,恶意代码必须能够利用 Web 技术(在此是 JavaScript),使浏览器自己运行攻击者希望运行的代码。一个简单的例子是,在发生一个基于浏览器的攻击时,受害者会发现其主页被篡改,或者当受害者在其浏览器地址栏中输入一个 URL 时,会被重定向到另一个网站。尽管这令人讨厌且很麻烦,但这些都不是最坏的情形。

许多基于浏览器的攻击被设计用来阻止受感染电脑发送通知或减少其他攻击。通常,对受害者浏览器进行的攻击会阻止他们访问恶意软件清除程序或使用 Web 订阅文件更新。其他威胁还包括浏览器代理和击键记录。

预防措施

保护自己不受基于浏览器的攻击比较容易,只需禁用 Java™ 技术、JavaScript 和 Microsoft® ActiveX® 控件即可。不过,这样做通常会阻止运行许多 Web 应用程序。相反,您应该确保 操作系统、浏览器软件和防病毒软件的及时更新。另外,还可以使用一个信誉良好的防火墙程序,并在下载文件和访问网站时小心谨慎。

 

2、SQL 注入

 

SQL 注入如何成为了 Ajax 安全的一个威胁?毕竟 Ajax 中没有 “S”。很简单,SQL 注入之所以构成威胁是因为 Ajax 在客户端运行。Web 应用程序服务器端仍然需要 SQL 数据库。

当攻击者在网站开发不完善的区域(比如一个表单)输入恶意代码时,就会发生 SQL 注入。如果受攻击网站比较脆弱,那么该数据库的所有内容都可能会曝光。密码数据库曝光或者从在线支付系统盗取信用卡数据使用的就是这种攻击方法。最近,入侵者利用这种方法从明星网站窃取粉丝邮箱地址。尽管没有盗窃财物,但是垃圾邮件发送者利用了这些邮箱地址,借用明星产品为幌子来传播恶意软件。

与其他 Web 技术一样,应减轻使用 Ajax 开发的应用程序中的 SQL 注入。不过,仅使用基于 JavaScript 的 sanitation 技术尚不足以防止这类利用。JavaScript 是在客户端运行而不是在服务器端运行,这才是发生 SQL 注入的主要原因。

预防措施

在使用 Ajax 时,要保护您的数据库,则必须验证用户输入,而且该验证是在服务器 端进行的。参数化语句或者预处理语句,这些都是为了阻止 SQL 注入,因为不能将值直接输入数据库或者 SQL 语句中。相反,在使用占位符(也称为绑定变量)时,占位符的值是通过一个单独的 API 调用提供的。

 

3、跨站点脚本

 

XSS 是注入攻击的另一个示例,恶意代码被注入到应用程序。易受 XSS 攻击的 Web 应用程序包括基于浏览器的脚本,就像那些常见的 Ajax 攻击一样。通常,攻击者利用这类弱点将恶意脚本传递给对该网站毫无戒心的访问者。这些脚本负责盗用身份,窃取 Cookie,暗中监视访客的 Web 使用,访问机密信息,甚至阻止服务攻击。

2010 年成为新闻焦点的著名的 XSS 攻击涉及到社会信息网络。这次攻击是从一个名为 @Matsta 的用户开始的,造成当浏览者鼠标滑过恶意消息时,出现 JavaScript 弹出窗口。其他 XSS 对该网站的攻击导致用户被重定向到一个调查网站或者内容不健康的网站。

预防措施

在使用 Ajax 进行开发时,可以采用以下步骤防止出现 XSS 漏洞

确保javascript变量被引用

使用javascript十六进制编码

使用javascript Unicode编码

使用JSON.parse或json2.js库来分析JSON

避免使用eval方法分析JSON

 

4、Ajax 桥接

 

Ajax 应用程序被构建用来连接托管它们的网站。作为一项安全措施,来自站点 A 的应用程序不能连接到站点 B。然而,许多站点依靠第三方网站和数据源来创建混搭网站。人们创建了 Ajax 桥接服务,通过一个主机提供 Web 服务,该服务将充当代理,用来在该浏览器上运行的 JavaScript 和第三方站点之间转发数据。使用 Ajax 桥接,现在站点 A 可以向来自站点 B 的访客提供数据或内容。

正如 Ajax 不是一项特定技术而是一个技术集合,桥接也不是一个特定漏洞。Ajax 桥接为恶意黑客提供了额外攻击途径,增加了威胁。诸如 XSS 和 SQL 注入等攻击可以通过 Ajax 桥接服务传递。尽管站点 B 可能用尽一切办法保护其 Web 应用程序免受访客带来的相应威胁,但是站点 A 可以使用 Ajax 桥接攻击站点 B,这常常被忽视。

预防措施

要避免桥接漏洞,则需要在使用桥接来访问时与第三方的站点之间建立信任。应该审核第三方站点以何种方式访问您的站点,并扫描可能被桥接利用的任何漏洞。