整理了一点关于ajax常见的问题 希望对大家有帮助
Ajax技术核心是XMLHttpRequest对象(简称XHR),这是由微软首先引入的一个特性, 其他浏览器提供商后来都提供了相同的实现。在XHR出现之前,Ajax式的通信必须借助一些hack手段来实现, 大多数是使用隐藏的框架或内嵌框架。 XHR的出现,提供了向服务器发送请求和解析服务器响应提供了流畅的接口。能够以异步方式 从服务器获取更多的信息,这就意味着,用户只要触发某一事件,在不刷新网页的情况下, 更新服务器最新的数据。 虽然Ajax中的x代表的是XML,但Ajax通信和数据格式无关,也就是说这种技术不一定使用XML。
IE7+、Firefox、Opera、Chrome和Safari都支持原生的XHR对象,在这些浏览器中创建XHR对象可以直接 实例化XMLHttpRequest即可。 如果是IE6及以下,那么我们必须还需要使用ActiveX对象通过MSXML库来实现。在低版本IE浏览器可能 会遇到三种不同版本的XHR对象,即MSXML2.XMLHttp、MSXML2.XMLHttp.3.0、MSXML2.XMLHttp.6.0。 我们可以编写一个函数 1、创建XHR对象 如果不考虑兼容性 var xhr = new XMLHttpRequest(); 如果需要考虑兼容性: 写一个方法: function createXHR(){ if(typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); }else if(typeof ActiveXObject != "undefined"){ var version = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.2.0", "MSXML2.XMLHttp" ]; for(var i = 0;i<3;i++){ /*return new ActiveXObject(version[i]);*/ //使用try{}catch{}防止在创建对象时出错 try{ return new ActiveXObject(version[i]); }catch(e){ //TODO handle the exception } } }else{ //如果都不支持,则抛出异常 throw new Error("您老的浏览器实在是不行了") //alert("您老的浏览器实在是不行了"); } } 2、调用open方法:准备发送请求(在使用xhr对象时,必须调用open方法) 它接受三个参数:要发送的请求类型(get、post)、请求的URL和表示是否异步。 注:必须对get与post的区别有所了解 //准备发送请求,以get方式请求,同步(flase表示同步,true表示异步) xhr.open("get","test.php",false); test.php: <?php echo Date("Y-m-d H:i:s"); ?> 3、发送请求:get不需要数据提交,则填写为null; //如果没有向服务器发送,则F12的network无发送提示,如果有,则有提示 send(null) 4、得到反馈信息:当请求发送到服务器端,收到响应后,响应的数据会自动填充XHR对象的属性。 那么一共有四个属性 属性名 说明 responseText 作为响应主体被返回的文本 responseXML 如果响应主体内容类型是"text/xml"或"application/xml",则返回包含响应数据的XML DOM文档 status 响应的HTTP状态 statusText HTTP状态的说明 5、打印服务器端返回的数据: xhr.responseText(); ?每次是否在点击刷新才可以实现 6、添加点击事件 //通过点击事件不断的向服务器发送请求,服务器会实时返回最新数据,这就是ajax的功能 //IE浏览器第一次会向服务器端发送请求,获取最新数据,而第二次他就默认获取的缓存数据,导致数据不是最新的 //解决方案:加随机数"test.php?random="+Math.random() document.addEventListener("click",function(){ var msg = document.getElementById("msg"); var xhr = createXHR(); xhr.open("GET","test.php?random="+Math.random(),false); xhr.send(null); msg.innerHTML = xhr.responseText; }) 7、接受响应之后,第一步检查status属性,以确定响应已经成功返回。一般而言HTTP状态代码为200作为成功的 标志。除了成功的状态代码,还有一些别的: HTTP状态码 状态字符串 说明 200 OK 服务器成功返回了页面 400 Bad Request 语法错误导致服务器不识别 401 Unauthorized 请求需要用户认证 404 Not found 指定的URL在服务器上找不到 500 Internal Server Error 服务器遇到意外错误,无法完成请求 503 ServiceUnavailable 由于服务器过载或维护导致无法完成请求 eg: alert(xhr.responseText); alert(xhr.status); alert(xhr.statusText); if(xhr.status == 200){ msg.innerHTML = xhr.responseText; }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } 我们判断HTTP状态值即可,不建议使用HTTP状态说明,因为在跨浏览器的时候,可能会不太一致。 疑问:和非ajax的获取时间的不同之处在哪? 解决思路: 1)创建一个test2.php: <script type="text/javascript"> document.addEventListener("click",function(){ alert("<?php echo Date('Y-m-d H:i:s')?>"); },false); </script> //注意到了吗?咱们每次必须点击刷新才可以
8、使用异步方式: 同步调用固然简单,但使用异步调用才是我们真正常用的手段。使用异步调用的时候, 需要触发readystatechange事件,然后检测readyState属性即可。这个属性有五个值: 值 状态 说明 0 未初始化 尚未调用open()方法 1 启动 已经调用open()方法,但尚未调用send()方法 2 发送 已经调用send()方法,但尚未接受响应 3 接受 已经接受到部分响应数据 4 完成 已经接受到全部响应数据,而且可以使用 eg: document.addEventListener("click",function(){ var msg = document.getElementById("msg"); var xhr = createXHR(); xhr.onreadystatechange = function(){ //alert(xhr.readyState) if(xhr.readyState == 4){ if(xhr.status == 200){ msg.innerHTML = xhr.responseText; }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open("GET","test.php?random="+Math.random(),true); xhr.send(null); //使用abort()方法可以取消异步请求,放在send()方法之后会报错。放在responseText之前会得到一个空值。
9、get与post 在提供服务器请求的过程中,有两种方式,分别是:GET和POST。在Ajax使用的过程中,GET的使用频率要比POST高。 //在普通web程序上,get一般是url提交请求,比如demo.php?name=wxx&sex=男 //post一般是web表单提交<form method = "post"><input type="text" name="name" value="wxx"/><input type="text" name="sex" value="男"/></form> //在ajax中的区别不大,只是写法问题 在了解这两种请求方式前,我们先了解一下HTTP头部信息,包含服务器返回的响应头信息和客户端发送出去的请求头信息。 响应头信息:服务器返回的信息,客户端可以获取,但是不可以设置 请求头信息:客户端发送的信息,可以设置但是不可以获取 我们只可以获取服务器返回回来响应头信息,无法获取向服务器提交的请求头信息, 自然自定义的请求头,在JavaScript端是无法获取到的 //使用getAllResponseHeaders()获取整个响应头信息 alert(xhr.getAllResponseHeaders()); //Date: Mon, 21 Mar 2016 13:24:56 GMT Server: Apache/1.3.35 (Win32) PHP/5.2.12 Connection: Keep-Alive X-Powered-By: PHP/5.2.12 Transfer-Encoding: chunked Keep-Alive: timeout=15, max=94 Content-Type: text/html //使用getResponseHeader()获取单个响应头信息 alert(xhr.getResponseHeader('Content-Type')); //使用setRequestHeader()设置单个请求头信息 xhr.setRequestHeader("myheader","wxx1111"); //放在open方法之后,send方法之前,一般没有用,在post提交请求时有用 9.1 get请求: 可以再php文件中通过print_r($_GET)来获取提交到服务器端的数据 <?php print_r($_GET); ?> //Array ( [random] => 0.0688955879304558 [name] => wxx ) <?php if($_GET["name"]=="wxx"){ echo "嘿嘿嘿"; } ?> document.addEventListener("click",function(){ var msg = document.getElementById("msg"); var xhr = createXHR(); xhr.onreadystatechange = function(){ //alert(xhr.readyState) if(xhr.readyState == 4){ if(xhr.status == 200){ msg.innerHTML = xhr.responseText; }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open("GET","test.php?random="+Math.random()+"&name=wxx",true); xhr.send(null); }) //使用该方式会有中文乱码问题(如果设置为BG2312) //解决办法: //1、ajax返回的数据其实是utf-8编码格式的 //特殊字符的问题 //解决办法 //需要通过encodeURIComponent来编码解决 var url = "test.php?random="+Math.random(); url = params(url,"name","wxx"); url = params(url,"sex","男"); xhr.open("GET",url,true); //test.php?random=0.9803138924762607&name=wxx&sex=男 function params(url,name,value){ //判断url中是否有?,如果没有就加?,如果有就加& url+=url.indexOf("?")==-1?"?":"&"; url+=name+"="+value; return url; } //如果在name中wxx改为了w&xx,则显示为 test.php?random=0.6418986094649881&name=wx&x&sex=男 //所以需要在参数位置加encodeURIComponent function params(url,name,value){ //判断url中是否有?,如果没有就加?,如果有就加& url+=url.indexOf("?")==-1?"?":"&"; url+=encodeURIComponent(name)+"="+encodeURIComponent(value); return url; } 9.2 post请求 POST请求可以包含非常多的数据,我们在使用表单提交的时候,很多就是使用的POST传输方式。 //第一步,发送方式改为post xhr.open('post', 'demo.php', true); //第二步,将需要的参数放入send方法中 //模拟表单提交 而发送POST请求的数据,不会跟在URL的尾巴上,而是通过send()方法向服务器提交数据。 一般来说,向服务器发送POST请求由于解析机制的原因,需要进行特别的处理。因为POST请求和Web表单提交是不同的,需要使用XHR来模仿表单提交。 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); document.addEventListener("click",function(){ var msg = document.getElementById("msg"); var xhr = createXHR(); var url = "test.php?random="+Math.random(); xhr.onreadystatechange = function(){ //alert(xhr.readyState) if(xhr.readyState == 4){ if(xhr.status == 200){ msg.innerHTML = xhr.responseText; // alert(xhr.responseText) }else{ // alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open("POST",url,true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send("name=wxx&sex='男'"); }); 总结:从性能上来讲POST请求比GET请求消耗更多一些,用相同数据比较,GET最多比POST快两倍 9.3 json回调 [ { "title":"A", "age":"100" }, { "title":"B", "age":"101" }, { "title":"C", "age":"102" }, { "title":"D", "age":"103" } ] document.addEventListener("click",function(){ var msg = document.getElementById("msg"); var xhr = createXHR(); var url = "demo.json?random="+Math.random(); xhr.onreadystatechange = function(){ //alert(xhr.readyState) if(xhr.readyState == 4){ if(xhr.status == 200){ //msg.innerHTML = xhr.responseText; var box = JSON.parse(xhr.responseText); msg.innerHTML = box; // alert(xhr.responseText) }else{ // alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open("GET",url,true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(null); }); 10、封装ajax 因为Ajax使用起来比较麻烦,主要就是参数问题,比如到底使用GET还是POST;到底是使用同步还是异步等等,我们需要封装一个Ajax函数,来方便我们调用 1、封装和调用 function createXHR(){ if(typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); }else if(typeof ActiveXObject != "undefined"){ var version = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.2.0", "MSXML2.XMLHttp" ]; for(var i = 0;i<3;i++){ /*return new ActiveXObject(version[i]);*/ try{ return new ActiveXObject(version[i]); }catch(e){ //TODO handle the exception } } }else{ throw new Error("您老的浏览器实在是不行了") //alert("您老的浏览器实在是不行了"); } } //封装ajax function ajax(){ } //调用ajax document.addEventListener("click",function(){ ajax(); }) 2、先封装get方式 //封装ajax function ajax(method,url,data,async){ var msg = document.getElementById("msg"); var xhr = createXHR(); url=url+"?random="+Math.random()+"&"+data; xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ alert(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(method,url,async); xhr.send(null); } //调用ajax document.addEventListener("click",function(){ ajax("GET","test.php","name=wxx&sex=男",true); }) //但是我们并不是需要在封装的那儿alert信息,我们需要在调用的地方取得他的值,所以我们需要返回值 if(xhr.status == 200){ return xhr.responseText } document.addEventListener("click",function(){ msg.innerHTML = ajax("GET","test.php","name=wxx&sex=男",true); }) //?出现了underfined,为什么呢,作用域的问题 function a(){ function b(){ return "123"; } return "456"; } /如何去做呢? //通过回调函数去解决 //封装ajax function ajax(method,url,data,async,obj){ var xhr = createXHR(); url=url+"?random="+Math.random()+"&"+data; xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(method,url,async); xhr.send(null); } //调用ajax document.addEventListener("click",function(){ ajax("GET","test.php","name=wxx&sex=男",true,{ success:function(text){ msg.innerHTML = text; } }); }) //那么,既然可以使用回调函数去解决参数问题, //封装ajax function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random()+"&"+obj.data; xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(obj.method,obj.url,obj.async); xhr.send(null); } //调用ajax document.addEventListener("click",function(){ ajax({ method:"get", url:"test.php", data:"name=wxx&sex=男", async:true, success:function(text){ msg.innerHTML = text; } }); }) //解决特殊字符问题,将name改为nam&e,将数据用键值对的形式传过去 //键值对转换为字符串 function params(data){ var arr = []; for(var i in data){ // alert(i)//可以获取键值 // alert(data[i])//可以获取值 arr.push(i+"="+data[i]); } alert(arr); } //封装ajax function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random()+"&"+params(obj.data); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(obj.method,obj.url,obj.async); xhr.send(null); } //调用ajax document.addEventListener("click",function(){ ajax({ method:"get", url:"test.php", // data:"nam&e=wxx&sex=男", data:{ "name":"wx&x", "sex":"男" }, async:true, success:function(text){ msg.innerHTML = text; } }); }) //将数组转换为字符串: alert(arr.join("&")); //再对 arr.push(i+"="+data[i]);进行编码 arr.push(encodeURIComponent(i)+"="+encodeURIComponent(data[i])); //考虑params(obj.data)的位置(get,post) function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random(); obj.data = params(obj.data); if(obj.method == "get"){ obj.url=obj.url+"&"+obj.data; } alert(obj.url) xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(obj.method,obj.url,obj.async); xhr.send(null); } //如果此时去掉随机数,则显示就会出错,所以需要判断时候有? obj.url = obj.url.indexOf("?")==-1?obj.url+"?"+obj.data:obj.url+"&"+obj.data; //如果采用post (if(obj.method == "post"){ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(obj.data); }else{ xhr.send(null); }) function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random(); obj.data = params(obj.data); if(obj.method == "get"){ /*obj.url=obj.url+"&"+obj.data; */ obj.url = obj.url.indexOf("?")==-1?obj.url+"?"+obj.data:obj.url+"&"+obj.data; } // alert(obj.url) xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; xhr.open(obj.method,obj.url,obj.async); if(obj.method == "post"){ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(obj.data); }else{ xhr.send(null); } } //上面是同步,那么异步呢 function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random(); obj.data = params(obj.data); if(obj.method == "get"){ /*obj.url=obj.url+"&"+obj.data; */ obj.url = obj.url.indexOf("?")==-1?obj.url+"?"+obj.data:obj.url+"&"+obj.data; } // alert(obj.url) if(obj.async == true){ xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } }; } xhr.open(obj.method,obj.url,obj.async); if(obj.method == "post"){ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(obj.data); }else{ xhr.send(null); } if(obj.async == false ){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } } 可以优化代码 (if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); })重复多次 function ajax(obj){ var xhr = createXHR(); obj.url=obj.url+"?random="+Math.random(); obj.data = params(obj.data); if(obj.method == "get"){ /*obj.url=obj.url+"&"+obj.data; */ obj.url = obj.url.indexOf("?")==-1?obj.url+"?"+obj.data:obj.url+"&"+obj.data; } // alert(obj.url) if(obj.async == true){ xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ callback() } }; } xhr.open(obj.method,obj.url,obj.async); if(obj.method == "post"){ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(obj.data); }else{ xhr.send(null); } if(obj.async == false ){ callback() } function callback(){ if(xhr.status == 200){ /*return xhr.responseText;*/ obj.success(xhr.responseText) }else{ alert("获取数据错误,错误信息为:"+xhr.status+"---"+xhr.statusText); } } } 补充://跨浏览器添加事件 function addEvent(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else if (obj.attachEvent) { obj.attachEvent('on' + type, function () { fn.call(obj); }); } } base.js 代码: //跨浏览器添加事件 function addEvent(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else if (obj.attachEvent) { obj.attachEvent('on' + type, function () { fn.call(obj); }); } }
//跨浏览器移除事件 function removeEvent(obj, type, fn) { if (obj.removeEventListener) { obj.removeEventListener(type, fn, false); } else if (obj.detachEvent) { obj.detachEvent('on' + type, fn); } }
//跨浏览器阻止默认行为 function preDef(evt) { var e = evt || window.event; if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } }
//跨浏览器获取目标对象 function getTarget(evt) { if (evt.target) { //W3C return evt.target; } else if (window.event.srcElement) { //IE return window.event.srcElement; } }
//跨浏览器获取字符编码 function getCharCode(evt) { var e = evt || window.event; if (typeof e.charCode == 'number') { return e.charCode; } else { return e.keyCode; } }