JavaScript Ajax之美~

fkdt2134 8年前
   <p>曾经有一段时期,因为开发人员对JavaScript的滥用导致其遭受了一段时间的冷门时期,不被大家看好,后来,到了2005年,Google公司的很多技术都是用了ajax之后,JavaScript才又火热了起来,可以说,是Ajax拯救了JavaScript,就目前来说,熟练使用Ajax已经成为了所有web开发人员必须掌握的技能。那么Ajax又是什么呢? 它的作用是什么呢?</p>    <h2><strong>第一部分:Ajax简介</strong></h2>    <p>Ajax即Asynchronous JavaScript +XML的简写,这一技术能够向服务器请求额外的数据而无需卸载页面,会带来更好地用户体验。Ajax的核心是XMLHttpRequest对象(简称XHR,这一对象受到chrome、safari、FF、opera等主流浏览器的支持),这是由微软首先引入的一个特性,IE 浏览器使用 ActiveXObject,后来浏览器提供商都提供了相同的实现。 XHR对象的存在,意味着当用户点击之后,不必刷新页面也可以从后台取得新数据,也就是说,可以试用XHR对象取得新数据,然后通过DOM方式将新数据插入到页面中,达到对网页的某部分进行更新的效果。 值得注意的是:虽然,Ajax中包含了xml,但是我们在无需刷新页面就得到的数据不一定是xml数据。</p>    <h2><strong>第二部分:XHR对象的创建</strong></h2>    <p>上面讲到,Ajax的核心是XMLHttpRequest对象,那么我们如何创建一个XMLHttpRequest对象呢?</p>    <p>首先,我们应当知道:所有浏览器都支持XMLHttpRequest对象,其中IE5和IE6使用ActiveXObject对象。并且现在所有浏览器(IE7+、FireFox、Chrome、Safari以及Opera)均内建了XMLHttpRequest对象。于是创建XMLHttpRequest对象的语法是:</p>    <pre>  <code class="language-javascript">var xhr = new XMLHttpRequest();</code></pre>    <p>刚刚提到老版本的Internet Explorer(IE5和IE6)使用的是ActiveXObject对象,所以语法是:</p>    <pre>  <code class="language-javascript">var axo = new ActiveXObject("Microsoft.XMLHTTP");</code></pre>    <p>注意:其中传入的“Microsoft.XMLHTTP”是不能改变的。</p>    <p>于是,为了应对所有的现代浏览器(包括IE5和IE6),请首先检查是否支持XMLHttpRequest对象:如果支持,则创建XMLHttpRequest对象;如果不支持,则创建ActiveXObject对象:</p>    <pre>  <code class="language-javascript">var xmlHttp=null;  if(window.XMLHttpRequest)  {         xmlHttp=new XMLHttpRequest();  }  else  {      xlmHttp=new ActiveXObject("Microsoft.XMLHTTP");  }</code></pre>    <p>关于这个应对所有现代浏览器的代码应当注意:</p>    <ul>     <li>我将xmlHttp的值设置为null,是因为null值表示一个空对象指针,而这也正是使用typeof操作符检测null值是会返回“object”的原因,因此:如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值。</li>     <li>之所以可以试用window.XMLHttpRequest来检测其是否存在,是因为XMLHttpRequest是window对象的属性。</li>    </ul>    <h2><strong>第三部分:XHR对象的用法(属性与方法等)</strong></h2>    <p>上面两部分,我们介绍XHR对象是什么以及怎么创建,这一部分我将谈一谈XHR对象的用法。</p>    <p>⑴.open()方法</p>    <p>既然XHR是一个对象,那么它就一定有自己的属性和方法。在使用XHR对象时,要调用的第一个方法是open()。它接受3个参数:</p>    <ol>     <li>要发送的请求的类型:get、post、put、delete等等。</li>     <li>请求的URL(这个URL既可以是绝对路径,也可以是相对路径)。</li>     <li>是否异步发送请求的布尔值:true表示异步发送请求,false表示同步发送请求。</li>    </ol>    <p>举例如下:</p>    <pre>  <code class="language-javascript">xhr.open("get","example.php",true);</code></pre>    <p>此时,这段代码会启动一个针对example.php的GET请求。 注意:open()方法并不会真正的发送请求而只是启动一个请求以备发送。 那么怎么才能发送特定的请求呢,这是就要用到send()方法了。</p>    <p>⑵. <strong>send()方法</strong></p>    <p>刚刚说到open()方法,只是开启(open),还没有发送,而send才是真正地发送。它接受一个参数:</p>    <ul>     <li><strong>作为请求主体发送的数据 </strong></li>    </ul>    <p>注意:如果不需要通过请求主体发送数据,则必须传入null。一般get请求不需要传入参数,而对于post请求,如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头。然后在 send() 方法中规定您希望发送的数据。这一部分会详细介绍,下面举一个简单例子:</p>    <pre>  <code class="language-javascript">xhr.open("get","example.php",true);  xhr.send(null);</code></pre>    <p>(3).XHR对象的几个属性</p>    <p>通过send()发送之后,会接受到响应,响应的数据会自动填充XHR对象的属性。主要有以下几种:</p>    <ul>     <li>responseText:作为响应主体被返回的文本</li>     <li>responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存包含着相应数据的XML DOM文档。</li>     <li>status:响应的http状态</li>     <li>statusText:Http状态的说明</li>    </ul>    <p>在接收到响应后,一般是先检查status属性,来确定响应是否成功返回,一般状态代码200表示成功(以2开头即表示成功),这是responseText就可以被访问了。 而状态代码为304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本, 因此这种响应也是有效的。于是可以通过下面的代码检测这两种状态:</p>    <pre>  <code class="language-javascript">xhr.open("get","example.php",false);   xhr.send(null);   if((xhr.status>=200&&xhr.status<300)||xhr.status==304){    alert(xhr.responseText);   }else{    alert("Request waw unseccessful:"+"xhr.status");   }</code></pre>    <p>XHR对象的readystate属性</p>    <p>使用Ajax我们当然还是希望发送异步请求的:如果发送同步请求,那么一旦网卡住了,这个页面就不会有任何反应而是继续等待响应,但是发送异步请求,即使网卡住,也不用担心,因为它是异步的。 而readystate属性可以检测到请求/响应过程的当前活动阶段 。它有5个取值,分别如下:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/32b03af35fa1571df29d01bcbf591ac9.png"></p>    <p>关键: 只要readystate的值改变(比如从0变为1,从1变为2等等),那么每次地改变都会触发readystatechange事件。并且可以通过这个时间检测每次状态变化后的readystate的值。 当值为4是最重要的,因为这事所有的数据已经准备就绪。看一个例子:</p>    <pre>  <code class="language-javascript">var xhr=new XMLHttpRequest();   xhr.open("get","example.php",false);   xhr.onreadystatechange=function(){    if(readystate==4){     if((xhr.status>=200&&xhr.status<300)||xhr.status==304){      alert(xhr.responseText);     }else{      alert("Request waw unseccessful:"+"xhr.status");     }    }   };   xhr.send(null);</code></pre>    <p>注意以下几点:</p>    <ul>     <li>xhr.onreadystatechange前面有一个on,这是因为我们使用的是DOM0级方法为XHR对象添加了时间处理程序, 没有利用addEventListener这种DOM2级方法,是因为并非所有的浏览器都支持DOM2级方法 。</li>     <li>这个例子中我们没有使用this对象,是因为onreadystatechange时间处理程序的作用域问题。 如果使用this对象,在有的浏览器中会导致函数执行失败或者导致发生错误。 因此,使用实际的XHR对象实例便利那个是一种较为可靠的方式。</li>    </ul>    <p>(4).abort()方法</p>    <p>在接受到响应之前,我们还可以使用abort()方法来取消异步请求,如下所示:</p>    <pre>  <code class="language-javascript">xhr.abort();</code></pre>    <p>在调用了这个方法之后,XHR对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。</p>    <p>(5)setRequestHeader()方法、getResponseHeader()方法、getAllResponseHeader()方法在第四部分介绍完之后讲解</p>    <h2><strong>第四部分:HTTP头部信息</strong></h2>    <p>因为使用Ajax和后台交互,那么就一定离不开http协议了。而HTTP请求和响应都会带有相应的头部信息。</p>    <p>在默认情况下,在发送XHR请求的同时,还会发送以下头部信息。</p>    <ul>     <li>Accept:浏览器能够处理的内容类型</li>     <li>Accept-Charset:浏览器能够显示的字符集</li>     <li>Accept-Encodding:浏览器能够处理的压缩编码</li>     <li>Accept-Language:浏览器当前设置的语言</li>     <li>Connection:浏览器与服务器之间链接的类型</li>     <li>Cookie:当前页面设置的任何Cookie</li>     <li>Host:发出请求的页面所在的域</li>     <li>Referer:发出请求页面的URI</li>     <li>User-Agent:浏览器的用户代理字符串   </li>    </ul>    <p>下面这张图片是我的chrome浏览器开发者工具下的network中截屏所得,大家可以对照参考:</p>    <p><img src="https://simg.open-open.com/show/8a21afd05be576bd70c1c08a310afe53.png"></p>    <p>我们还可以通过 <strong>setRequestHeader()</strong> 方法来设置自定义的请求头部信息。这个方法接收两个参数:头部字段的名称和头部字段的值。并且我们必须在open()方法之后,在send()方法之前来调用setRequestHeader()方法。举例如下:</p>    <pre>  <code class="language-javascript">var xhr=new XMLHttpRequest();    xhr.open("get","example.php",true);    xhr.setRequestHeader("myHeader","myValue");    xhr.send(null);</code></pre>    <p>这里只需要注意: 这里传入的头部字段的名称最好是自定义的,而不要使用浏览器正常发送的字段名称,否则有可能会影响浏览器的响应。 (因为有的浏览器允许开发人员重写默认的头部信息,而有的浏览器是不允许开发人员重写默认的头部信息的)。</p>    <p>除了可以为请求头部增加自定义的头部字段,我们还可以获取头部字段。我们可以调用XHR对象的getResponseHeader()方法并传入一个头部字段名称,便可以获得响应头部信息。还可以调用XHR对象的getAllResponseHeaders()方法取得一个包含所有头部信息的长字符串。</p>    <p>如下所示:</p>    <pre>  <code class="language-javascript">var myHeader=xhr.getResponseHeader("myHeader");    var allHeaders=xhr.getAllResponseHeaders();</code></pre>    <h2><strong>第五部分:GET请求</strong></h2>    <p>get请求用于向服务器查询某些信息。 注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的。  但是,有时候可能会出现问题,即查询字符串的格式有问题。查询字符串的每个参数的名称和值都必须使用 encodeURIComponent() 进行编码,然后才能放到URL的末尾;而且所有的名值对都必须用&分隔。如下所示:</p>    <pre>  <code class="language-javascript">xhr.open("get","example.php?name1=value1&name2=value2",true);</code></pre>    <p>而下面的这个函数可以辅助向现有的URI的末尾添加查询字符串:</p>    <pre>  <code class="language-javascript">function addURIParam(url,name,vaule){     url+=(url.indexOf("?")==-1?"?":"&");     url+=encodeURIComponent(name)+"="+encodeURIComponent(value);     return url;    }    var url="example";    url=addURIParam(url,"name","zzw");    url=addURIParam(url,"sex","male");    xhr.open("get",url,false);</code></pre>    <p>实际上,函数中的第一句是先判断url后面有没有查询字符串,如果没有,就添加?,如果有,就添加&,因此,最终的url为"example.php?name=zzw&sex=male"。</p>    <p>另外,对于get请求需要注意:</p>    <ul>     <li>GET请求可以被缓存</li>     <li>GET请求保留在历史记录中</li>     <li>GET请求可悲收藏为书签</li>     <li>GET请求不应该在处理敏感数据时使用(因为查询字符串是暴露的,任何人都可以看到)</li>     <li>GET请求有长度限制,超过最大长度后一般无法提交</li>     <li><strong>GET请求只应当用于取回数据</strong></li>    </ul>    <h2><strong>第六部分:POST请求</strong></h2>    <p>POST请求的使用频率仅次于GET请求,通常用于向服务器中发送应该被保存的数据。 请注意,查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的。 而GET请求却不是这样的。POST请求的主体可以包含很多的数据,而且格式不限。</p>    <p>默认情况下,服务器对post请求和提交web表单的请求不会一视同仁,因此, 我们可以试用XHR对象和模仿表单提交:首先将Content-Type头部信息设置为application/x-www-form-urlencoded,也就模仿成了表单提交时的内容类型(赞一个!)。 接着需要在以适当的格式创建一个字符串,post数据的格式和查询字符串格式相同,如果需要将页面中表单的数据序列化,在通过XHR发送到服务器,那么就要使用serialize()函数来创建这个字符串。下面举两个例子:</p>    <pre>  <code class="language-javascript">xhr.open("POST","example.php",true);  xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");  xhr.send("fname=Bill&lname=Gates");</code></pre>    <p>这里我们没有将字符串序列化。</p>    <pre>  <code class="language-javascript">xhr.open("POST","example.php",true);  xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");  var form=document.getElementById("user-info");  xhr.send(serialize(form));</code></pre>    <p>这里我们使用serialize()函数进行了序列化。</p>    <p>另外,对于post请求需要注意:</p>    <ul>     <li>POST请求不会被缓存</li>     <li>POST请求不会保留在浏览器历史记录中</li>     <li>POST请求不能被收藏为书签</li>     <li>POST请求对数据长度没有要求</li>    </ul>    <p>讲过了POST请求和GET请求,那么它们之间的区别是什么呢?</p>    <p><img src="https://simg.open-open.com/show/084503c85196edcf196a8a659d37db2f.png"></p>    <h2><strong>第七部分:同源策略</strong></h2>    <p>通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略,又称为同源策略。那么什么使同源策略呢?</p>    <p>同源策略,它是由Netscape提出的一个著名的安全策略,默认情况下,XHR对象只能访问与包含他的页面位于同一个域中的资源,这种安全策略可以预防某些恶意行为。现在所有支持JavaScript的浏览器都会使用这个策略,这种安全策略可以预防某些恶意行为,比如,A网站是一家银行,如果用户登陆了以后,其他的网站可以读取A网站的Cookie,那么其他网站就可以为所欲为了。但是,实现合理的跨域请求对开发某些浏览器的应用程序也是至关重要的。后续的文章我会介绍跨域资源共享的知识。这里仅介绍同源策略。</p>    <p>所谓 <strong>同源</strong> 是指: <strong>协议、域名和端口相同</strong> 。</p>    <p>举例说:http://www.cnblogs.com/dir/page.html这个网址。</p>    <p>协议:http://</p>    <p>域名:www.cnblogs.com</p>    <p>端口:80(默认端口可以省略)。</p>    <p>对于这个网址的同源情况如下:</p>    <ul>     <li>http://www.cnblogs.com/cat/index.html (同源)</li>     <li>http://cnblogs.com/dir/page.html(不同源-域名不同)</li>     <li>https://cnblogs.com/dir/page.html(不同源-协议不同)</li>     <li>http://www.cnblogs.com:81/dir/page.html(不同源-端口不同)</li>    </ul>    <p> </p>    <p> </p>    <p>来自:http://www.cnblogs.com/zhuzhenwei918/p/6083797.html</p>    <p> </p>