ajax经验分享

AJAX即“Asynchronous Javascript And XML”,说白了就是异步JavaScript+XML,是指一种创建交互式网页应用、创建快速动态网页的网页开发技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。 而传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面。

前言

Adaptive Path公司的Jesse James Garrett这样定义Ajax:

Ajax不是一种技术,实际上,它由几种蓬勃发展的技术以新的强大方式组合而成。Ajax包含: 基于XHTML和CSS标准的表示; 使用Document Object Model进行动态显示和交互; 使用XMLHttpRequest与服务器进行异步通信; 使用JavaScript绑定一切。

而我们接触比较多的AJAX技术就是表单异步提交、天气信息显示,当然还有在线地图服务,Google地图就是率先将AJAX技术应用到切合实际的技术当中去的。

AJAX技术中用到的三个比较重要的技术点:Javascrip、Dom(文档对象模型)、XMLHttpRequest对象,这个我们会在后面慢慢的接触到。当你了解了以上的三项技术,那么你就可以接下来学习AJAX应用了。

一、创建XMLHttpRequest对象

Ajax 的核心是 JavaScript 对象 XMLHttpRequest。该对象在 Internet Explorer 5 中首次引入,它是一种支持异步请求的技术。简而言之,XMLHttpRequest使您可以使用 JavaScript 向服务器提出请求并处理响应,而不阻塞用户。

首先我们需要创建XmlHttpRequest对象 (字母较长,我在下面就称它为XHR对象)。由于浏览器兼容性问题,创建方式不同,我们首先创建一个支持多浏览器的 XMLHttpRequest 对象。

下面的代码基本上兼容了所有的浏览器,在需要创建XHR对象的地方运行下面的函数就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function GetXmlHttpObject()
{
  var xmlHttp=null;
  try
    {
    // Firefox, Opera 8.0+, Safari
    xmlHttp=new XMLHttpRequest();
    }
  catch (e)
    {
    // Internet Explorer
    try
      {
      xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
      }
    catch (e)
      {
      xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
      }
    }
  return xmlHttp;
}

也可以这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
funciton getXHR(){
  var xhrObj;
  try {
    xhrObj = new XMLHttpRequest();
  } catch (e) {
    var aTypes = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
    var len = aTypes.length;
    for (var i = 0; i < len; i++) {
      try {
        xhrObj = new ActiveXObject(aTypes[i]);
      } catch (e) {
        continue;
      }
      break;
    }
  }
  finally {
    return xhrObj;
  }
}

其实一般我用的下面的代码:

1
2
3
4
5
6
7
8
9
var xmlhttp;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

二、向服务器发送请求

XMLHttpRequest 对象用于和服务器交换数据。如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();</cc>
<p>XMLHttpRequest 对象如果要用于 AJAX 的话,其 open() 方法的 async 参数必须设置为 true</p>
<p>发送求情有两种方法,get和post。与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。然而,在以下情况中,请使用 POST 请求:</p>

<blockquote>
-无法使用缓存文件(更新服务器上的文件或数据库)
-向服务器发送大量数据(POST 没有数据量限制)
-发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠</blockquote>

<p>1、GET方法:
GET方法请求的数据是通过url来传递的,所以我们在open方法中要把请求的字段写进url里。</p>
<p>一般格式:</p>
[cc lang="javascript"]
xmlhttp.open("GET","demo_get.asp",true);
xmlhttp.send();

如果您希望通过 GET 方法发送信息,请向 URL 添加信息:

1
2
xmlhttp.open("GET","demo_get2.asp?fname=Bill&amp;lname=Gates",true);
xmlhttp.send();

2、post方法:

post和get的区别是,post需要用setRequestHeader() 来添加一个http头,来注明格式

1
2
3
xmlhttp.open("POST","ajax_test.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Bill&amp;lname=Gates");

3、 onreadystatechange事件

当使用 async=true 时,请规定在响应处于 onreadystatechange 事件中的就绪状态时执行的函数:

1
2
3
4
5
6
7
8
9
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();

如需使用 async=false,将 open() 方法中的第三个参数改为 false就行了。一般不推荐使用 async=false,但是对于一些小型的请求,也是可以的。JavaScript 会等到服务器响应就绪才继续执行。如果服务器繁忙或缓慢,应用程序会挂起或停止。

当使用 async=false 时,请不要编写 onreadystatechange 函数 - 把代码放到 send() 语句后面即可:

1
2
3
xmlhttp.open("GET","test1.txt",false);
xmlhttp.send();
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

三、服务器响应

获得来自服务器的响应,需要使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。

1、responseText 属性

如果来自服务器的响应为text,请使用 responseText 属性。responseText 属性返回字符串形式的响应,因此可以这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<p>2、responseXML 属性</p>
<p>如果来自服务器的响应是 XML,而且需要作为 XML 对象进行解析,请使用 responseXML 属性:</p>
<p>比如返还的XML响应内容为:</p>
 
[cc lang="javascript"]&lt;bookstore&gt;
&lt;book category="children"&gt;
&lt;title lang="en"&gt;Harry Potter&lt;/title&gt;
&lt;author&gt;J K. Rowling&lt;/author&gt;
&lt;year&gt;2005&lt;/year&gt;
&lt;price&gt;29.99&lt;/price&gt;
&lt;/book&gt;
&lt;book category="cooking"&gt;
&lt;title lang="en"&gt;Everyday Italian&lt;/title&gt;
&lt;author&gt;Giada De Laurentiis&lt;/author&gt;
&lt;year&gt;2005&lt;/year&gt;
&lt;price&gt;30.00&lt;/price&gt;
&lt;/book&gt;
&lt;/bookstore&gt;

解析的代码如下:

1
2
3
4
5
6
7
8
xmlDoc=xmlhttp.responseXML;
txt="";
x=xmlDoc.getElementsByTagName("book");
for (i=0;i&lt;x.length;i++)
  {
  txt=txt + x[i].childNodes[0].nodeValue + "&lt;br /&gt;";
  }
document.getElementById("myDiv").innerHTML=txt;

四、onreadystatechange 事件

当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState 属性存有 XMLHttpRequest 的状态信息。

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

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

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

200: "OK"

404: 未找到页面

注:onreadystatechange 事件被触发 5 次(0 - 4),对应着 readyState 的每个变化。 在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。

当 readyState 等于 4 且状态为 200 时,表示响应已就绪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<h4>五、callback回调函数</h4>
<p>如果您的网站上存在多个 AJAX 任务,那么您应该为创建 XMLHttpRequest 对象编写一个标准的函数,并为每个 AJAX 任务调用该函数。callback 函数是一种以参数形式传递给另一个函数的函数。该函数调用应该包含 URL 以及发生 onreadystatechange 事件时执行的任务(每次调用可能不尽相同):</p>
 
[cc lang="javascript"]
var xmlhttp;
function loadXMLDoc(url,cfunc)
{
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=cfunc;
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
function myFunction()
{
loadXMLDoc("/ajax/test1.txt",function()
  {
  if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)
    {
    document.getElementById("odiv").innerHTML=xmlhttp.responseText;
    }
  });
}

上面的myFunction()函数就可以在使用的时候调用,比如在一个div节点加入onclick事件,当点击的时候会调用myFunction()函数,再调用loadXMLDoc()函数,创建XHR对象,发送请求,然后如果readyState==4并且status==200,就在id为odiv的地方加载xmlhttp.responseText。

下面附上get和post方法完整的例子:

get:
1
2
3
4
5
6
7
8
9
10
11
12
var request = new XMLHttpRequest();
    request.open("GET", "server.php?number=" + document.getElementById("keyword").value);
    request.send();
    request.onreadystatechange = function() {
        if (request.readyState===4) {
            if (request.status===200) {
                document.getElementById("searchResult").innerHTML = request.responseText;
            } else {
                alert("发生错误:" + request.status);
            }
        }
    }
post:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var request = new XMLHttpRequest();
    request.open("POST", "server.php");
    var data = "name=" + document.getElementById("staffName").value
                      + "&amp;number=" + document.getElementById("staffNumber").value
                      + "&amp;sex=" + document.getElementById("staffSex").value
                      + "&amp;job=" + document.getElementById("staffJob").value;
    request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    request.send(data);
    request.onreadystatechange = function() {
        if (request.readyState===4) {
            if (request.status===200) {
                document.getElementById("createResult").innerHTML = request.responseText;
            } else {
                alert("发生错误:" + request.status);
            }
        }
    }

跨域问题的解决办法

说到ajax一般肯定会有跨域问题存在,那什么是跨域呢?

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。这里把涉及到跨域的一些问题简单地整理一下。

一、什么是跨域

简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。

20160516151541_E0ADEAAF2E2349fa98398679FABD9122 特别注意两点:

1、如果是协议和端口造成的跨域问题“前台”是无能为力的。

2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。 “URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

二、解决办法

一般最常用的解决办法有三种:

1、代理

通过在同域名的web服务器端创建一个代理: 北京服务器:www.beijing.com 成都服务器:www.chengdu.com

比如在北京的web服务器后台(www.beijing.com/server.php)来调用成都服务器(www.chengdu.com/server.php)的服务,然后再把响应结果返回给前端,这样前端调用北京同域名的服务和调用成都的服务效果相同了。 这样做的好处是,绕开了a前端调用跨域的b服务器的服务,而是用a后台的服务来调用b服务器的服务,然后在用a前端来调用a服务器的服务,a前端和a服务器当然不存在跨域问题,毕竟在同一个url下。

2、JSONP

JSONP可以解决主流浏览器的跨域数据访问问题。不过只能发送get请求不能发送post请求。

用jsop就要用到jQuery ajax,在ajax方法中多加入两个属性即可:

dataType: "jsonp"和jsonp: "callback"。

例如:

1
2
3
4
5
6
7
8
9
$.ajax({
            type: "GET",    
            url: "http://127.0.0.1:8000/ajaxdemo/serverjsonp.php?number=" + $("#keyword").val(),
            dataType: "jsonp",
            jsonp: "callback",
            success: function(data) {
                    $("#searchResult").html(data.msg);
            },
        });

3、XHR2

HTML5的提供的XMLHttpRequest Level2已经实现了跨域访问以及其他的一些新功能,XHR2是html5新增的一项标准功能,因此 IE10以下 版本的浏览器是不支持 的,因此,如果要求兼容IE9或更低版本的ie浏览器,会导致使用此种方式的跨域请求以及传递Cookie的计划夭折,最终还得回归JSONP(因为目前主流的处理方式是使用JSONP,不仅易于实现,而且兼容性好,可查的资料也很多。)

如果你的服务器是PHP写的,在服务器端加入以下代码即可(如果不是,请查阅相关代码,方法都是一样的):

1
2
// 指定可信任的域名来接收响应信息(推荐)
<?php  header('Access-Control-Allow-Origin:http://A.abc.com'); ?>

或加入

1
2
// 使用通配符 * ,表示当前服务端通话任何域名发起请求(不推荐,因为不安全)
<?php header('Access-Control-Allow-Origin:*'); ?>

跨域解决后,如果还要操作Cookie,还得继续补增响应头:

1
 <?php  header('Access-Control-Allow-Credentials:true'); ?>

还需要将 XMLHttpRequest 对象的 withCredentials 属性设置为 true,JQuery1.5.1+ 就开始提供了相应的字段,使用方式如下:

1
2
3
4
5
6
7
$.ajax({
url:"B.abc.com",
xhrFields:{
withCredentials:true//允许ajax请求携带cookie信息  
},
crossDomain:true
});

这样就可以收到 Cookie 了。

设置 withCredentials 为 true 的请求中会包含 B.abc.com端的所有Cookie,这些Cookie仍然遵循同源策略,所以,你只能访问其中和 B.abc.com同根域的Cookie,而无法访问其他域的Cookie。

Access-Control-Allow-Origin实则是html5 Cross-Origin Resource Sharing(Cross-Origin Resource Sharing,跨域资源共享,简称 CORS,可以作为一种跨域请求以及响应的解决方案)实现的最重要的一点参数配置。如果你不需要接收cookie,那么在服务器端一般加入下面两行代码即可:

1
2
header('Access-Control-Allow-Origin:*');//根据需要选择是否指定域名
header('Access-Control-Allow-Methods:POST,GET');

附: 禁用chrome本地安全策略,不用配服务器环境也能发起ajax请求:

chrome 桌面快捷键 右键属性 在快捷方式标签下的“目标”框中加入 --disable-web-security,重启浏览器即可

更多的办法可以参考链接(介绍的很详细):http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

2 COMMENTS
  1. 2016/05/30
    龙笑天

    举几个实际的例子,更能让人懂

    • 2016/05/31
      那樊笼
      @龙笑天 这是获取数据的第一步,下一步就是对数据操作了,怎么操作这是按项目需求来的,我也就没说,而且ajax核心我觉得就是这些。
LEAVE A REPLY
loading
正在赶回来……