Ajax技术出现的意义:
向服务器请求额外的数据而无序卸载页面,带来更好的用户体验,页面无刷新技术。
1、Ajax的核心是XMLHttpRequest对象(简称XHR),创建XHR对象
如下兼容处理,创建XHR对象 function createXhr(){ if(typeof XMLHttpRequest != undefined){ return new XMLHttpRequest();//使用XMLHttpRequest构造函数来创建XHR对象,适用于IE7及以上版本,如果兼容到IE7,下边就可以省略了。 }else if(typeof ActiveXObject != undefined){ //适合IE7之前的版本 if(typeof arguments.callee.activeXString != "string"){ var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML.XMLHttp"]; for(var i = 0,len=versions.length;i<len;i++){ try{ var xhr = new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; return xhr; }catch (ex){ //跳过 } } } return new ActiveXObject(arguments.callee.activeXString); }else{ throw new Error("No XHR object available."); }; } var xhr = new createXhr(); xhr;
结果如下:
2、XHR的方法
1、open()方法
//客户端:启动一个请求,以备发送 xhr.open("get","example.php",false);
传入三个参数:
第一个参数:请求的方法,get||post||delete;
第二个参数:请求的地址,相对与当前页面的路径;
第三个参数:是否异步?true表示异步||false 表示同步,一般情况下都是选择异步。
2、send()方法
//客户端:发送请求 xhr.send(null);
接收一个参数,作为请求的主体发送的数据(序列化后的data)。如果不需要传数据就必须传入 null。
调用send()之后,请求就会被分派到服务器。
3、服务器响应
服务器响应的数据会自动填充XHR对象的属性,相关的属性简介如下:
responseText:作为相应主体被返回的文本。
responseXML:如果响应的数据的内容类型是text/xml或者application/xml,那么这个属性就会保存响应数据的XML DOM文档。
status:响应的HTTP状态。
statusText:HTTP状态的说明。
在客户端接受到服务器的响应之后:
首先要检查status属性,以确定响应是否已经成功的返回了。
状态码200:HTTP请求成功,此时responseText属性内容已就绪,(在内容类型正确的情况下,responseXML也是可以访问的了)。
状态码304:请求的内容在服务器端没有改变,可以直接使用浏览器端的缓存的版本,当然请求也是成功的。
正确的处理响应的函数如下:这里是同步发送时的处理(函数顺序执行),直接通过status来进行判断是否成功
var xhr = new createXhr(); xhr.open("get","example.php",false);//同步发送,需要等到接收成功之后js才能继续向下执行。 xhr .send(null); if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); } else { console.log("Request was unsuccessful:" + xhr.status); }
响应的主题都会保存到responseText属性中,而对于非XML数据,responseXML属性的值将为 null。
对于异步发送的请求(true),可以通过检测XHR对象的readyState属性,该属性表示响应活动的当前活动阶段。
该属性有如下的取值:
0:未初始化。尚未调用open()方法。
1:启动。调用了open(),但是没有调用send()。
2:发送。已经调用了send()方法,但是还没有接收到响应。
3:接收。接受到部分响应。
4:完成。接收到了全部的响应。
在请求状态改变的时候会触发readystatechange事件,可以利用这个事件来检测每次状态变化后的readyState的值,这样就可以在响应完成的时候确定响应是否成功,并进行接下来的操作。
注意:为了保证兼容性,需要在open() 方法之前指定onreadystatechange事件处理程序。
var xhr = new createXhr(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); } else { console.log("Request was unsuccessful:" + xhr.status); } } } xhr.open("get","example.php",true);//异步发送,发送请求之后,保留状态监听事件,继续执行后边的操作,如果响应成功,4&&200||304就会执行处理函数。 xhr .send(null);
在接受到相应之前还可以调用: xhr.abort();方法来取消异步请求。
3、HTTP头部信息
头部信息非为请求头部和响应头部。
默认情况下,发送XHR请求的时候,默认发送下列头部信息:
Accept:浏览器能够拿来处理的内容类型。
Accept-Charset:浏览器能够现实的字符集。
Accept-Encoding:浏览器能够处理的压缩编码。
Accept-Language:浏览器当前设置的语言。
Connection:浏览器与服务器之间的连接类型。
Cookie:当前页面设置的任何cookie。
Host:发出请求的页面所在的域。
referer(将错就错,原本应该是referrer:推荐人):发出请求页面的URI。document.referrer:返回当前文档的url
User-Agent:浏览器的用户代理字符串。
可以使用的方法:
setRequestHeader("MyHeader","Myvalue");设置自定义的请求头部信息。该方法必须位于open()与send()方法之间调用才可以,准备发起请求,还未发起。
getRequestHeader("Header");获取指定名称的头部信息。
getAllRequestHeaders();获取所有的头部信息的长字符串。
4、典型的请求
1、GET请求:用于查询服务器的信息。需要的时候需要添加查询字符串。
常出现的一个问题就是查询字符串的个是有问题,所有的名称和值都需要使用encodeURIComponent() 进行编码。
如下辅助函数可以解决在url后边添加查询字符串的问题:
function addUrlParam(url,name,value){ url += (url.indexOf("?") == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" +encodeURIComponent(value); return url; }
使用如下:
var url = "https://www.baidu.com"; url = addUrlParam(url,"name","dadaoshenyi");//"https://www.baidu.com?name=dadaoshenyi"
2、post请求:通常用于向服务器发送需要保存的数据,此时数据应该作为请求send发送的主体,发送给服务器。
请求主体是一个类似这样的字符串:name=sdfds&value1=sdfsdfds&value2=sdfsdf......;里边的字符都是经过编码的。
5、XMLHttpRequest2级
1、FormData
内置的对象:用于序列化表单以及创建与表单个是相同的数据(用于XHR传输)。最终传递给send()方法。
var form = document.getElementById("user-info"); xhr.send(new FormData(form));
2、超时设定:timeout属性,用于表示请求在多少毫秒后就终止了。
设定超时时间,在超出时间之后检测ontimeout事件:
xhr.timeout = 1000;//设定时限为1s xhr.ontimeout = function(){ console.log("Request did not return in a second"); }
3、overrideMimeType()方法
6、进度事件
6个进度事件
1、loadstart:接受到响应数据的第一个字节的时候触发。
2、progress:接收响应期间一直触发。周期性的触发,也会接受到一个event对象,其target属性指向XHR对象。
3、error:请求发生错误的时候触发。
4、abort:调用abort()方法的时候触发。
5、load: 接受到完整的响应的时候触发。用以替代readystatechange事件,响应接收完毕后触发load事件。这也就是说没有再检查readyState属性了。onload事件处理程序会接受到一个event对象,其target指向XHR对象的实例。
6、loadend:通信完成时或者触发error、abort或load事件后触发。
7、跨域资源共享:CORS(Cross - Origin Resource Sharing),W3C的一个工作草案,用于突破跨域安全策略来进行资源共享
背后的原理:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求应该是成功还是失败。受限发送一个option请求,不发送数据。确认可以跨域再发后续的请求。
跨域安全策略:同域名、同端口号、同协议。
如下:在发送请求的时候,客户端要添加一个额外的头部,包含页面请求的源信息(协议、域名和端口号),
Origin:http://www.changyangzhe.com
如果服务器认为可以接收这个请求就会回发一个相同的源信息:
Access-Control-Allow-Origin:http://www.changyangzhe.com
这个时候浏览器收到这个信息,就会发送请求,如果不匹配就会驳回请求。
跨浏览器的CORS
function createCORSRequest (method,url) { var xhr = createXHR(); if ("withCredentails" in xhr) { xhr.open(method,url,true); } else if (typeof XDomainRequest != "undefined") { xhr = new XDomainRequest(); xhr.open(method,url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get","http://www.somewhere-else.com"); if(request) { request.onload = function (){ //相关代码 } request.send(); }
8、其他跨域技术
1、图像Ping
原理:网页可以从任何地方加载任何图像。
2、JSONP,详细参考:说说JSON和JSONP,也许你会豁然开朗
JSONP:JSON with padding(填充式JSON或参数式JSON)
如下的样式:callback({"name":"changyangzhe"});这样的文件保存在远程的js文件中,数据就是传入的参数,调用的函数名就是callback。
由两部分组成:回调函数和数据。
回调函数:用来当响应来到的时候应该在页面中调用的函数,回调函数的名字一般在请求中指定。
数据:就是传入回调函数中的JSON数据。
实现思路:
1、前端创建script标签,设置src,添加到head中;
2、后台返回一个js变量JSONP,这个JSONP就是请求得到的JSON数据;
3、回调完成之后删除script标记。
原理:跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理。
方案:web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
如下实例:
http://free.net/json/?callback=handleRequest
这里是在请求一个JSONP的地理定位服务。这里的回调函数的名字叫handleRequest()。
JSONP是通过动态<script>元素来使用的,使用时可以为src指定一个跨域URL,与 <img>类似,可以不受限制的从其他域加载资源。
因为JSONP是有效的js代码,所以在请求完成之后,即在JSONP响应加载到页面中以后,就会立即执行。
本地文件如下:
function handleRequest(response){ console.log("you are at IP address " + response.ip + ",which is in" + response.city + "," + response.region_name); } var script = document.createElement("script");
//提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
script.src = "http://free.net/json/?callback=handleRequest";//远程的回调函数名
document.body.insertBefore(script,document.body.firstChild);
远程的文件:
如romot.js,里边的内容如callback("ip":"123456789","city":"hangzhou");
特点:支持双向的通信
不足:不能防止其他域的恶意代码;判断JSONP请求成功与否并不容易。
3、jQuery使用jsonp的代码
//还是忍不住吐槽,虽然jquery也把jsonp归入了ajax,但其实它们真的不是一回事儿,jsonp不是ajax的一个特例 //但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。 //其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。 jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998", dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据 success: function(json){//自动帮你生成回调函数并把数据取出来供success属性方法来调用,是不是很爽呀,也就不用动态生成标签了 alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。'); }, error: function(){ alert('fail'); } }); }); //请求的页面生成如下一段代码,这是服务端要生成的js片段 flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5 });
9、ajax请求与表单提交的区别与联系
有如下几种区别:
1. Ajax在提交、请求、接收时,都是异步进行的,网页不需要刷新;Form提交则是新建一个页面,哪怕是提交给自己本身的页面,也是需要刷新的;
2. Ajax在提交时,是在后台新建一个请求;F却是放弃本页面,而后再请求;
3. A必须要使用JS来实现,不启用JS的浏览器,无法完成该操作;F却是浏览器的本能,无论是否开启JS,都可以提交表单;
4. A在提交、请求、接收时,整个过程都需要使用程序来对其数据进行处理;F提交时,却是根据你的表单结构自动完成,不需要代码干预。
典型的jquery,ajax实现,这里返回的是一个promise对象:
$.ajax({ type: 'GET', async: false, url: 'http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx/getCountryCityByIp?callback=?', data:{theIpAddress:host_ip[0]}, dataType: 'jsonp', jsonp: "callback", success: function(msg){ alert(JSON.stringify(msg)); }, error:function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.status); alert(XMLHttpRequest.readyState); alert(XMLHttpRequest.responseText); alert(textStatus); alert(errorThrown); console.log(textStatus); } });