初始ajax和跨域
来源:互联网 发布:淘宝店铺关注怎么刷 编辑:程序博客网 时间:2024/05/18 03:37
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术,它是一种从页面向服务器请求数据的技术。
AJAX = 异步+js+xml
XMLHttpRequest 对象
创建该对象
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"); }
常用方法和属性
接收响应后,先检查status属性,确定响应已经返回后再进行其他操作。
get 最常用于向服务器查询某些信息。注意:传入open方法中的url末尾的字符串必须经过正确的编码,构建一个编码函数。
function addURLParam(url,name,value){ url += (url.indexOf("?") == -1 > "?" : "&"; url += encodeURIComponent(name) + "=" +encodeURIComponent(value); return url;}
post 通常向服务器发送应该保存的数据。当send XML DOM文档时,传入的文档要经过序列化。
jquery中有一个ajax方法,可以很方便的实现ajax。
下面我们看一下利用jquery实现ajax的代码
<body><h1>员工查询</h1><input type="text" id="userid" /><button id="search">查询</button><p id="result"></p><h2>创建员工</h2><label>请输入员工姓名:</label><input type="text" id="username" /><br/><label>请输入员工编号:</label><input type="text" id="user_id" /><br/><label>请选择员工性别:</label><select id="usersex"><option>男</option><option>女</option></select><br/><label>请选择员工职位:</label><input type="text" id="userjob" /><br/><button id="save">保存</button><p id="create"></p><!-- 引入jquery库 --><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script><script>/*给查询按钮和保存按钮添加响应函数,实现查询和添加员工功能*///jquery初始化$(document).ready(function(){ $("#search").click(function(){ $.ajax({ type:"GET", //type:请求的类型,GET,POST url:"http://121.195.170.175:8077/ajaxdemo/serverjquery.php?number="+$("#userid").val(), dataType:"json", //预期服务器返回的数据类型,不指定的话,jQuery自动根据http包中的MIME信息来判断,一般我们采用json格式 success: function(data){ if(data.success){ $("#result").html(data.msg); } else{ $("#result").html("fault happened " + data.msg); } }, //一个方法,请求成功后的回调函数。传入返回后的数据以及包含成功代码的字符串。 error:function(jqXHR){ $("#result").html("fault happened " + jqXHR.status); }, //一个方法,请求失败时调用此函数。传入XHR对象 }); }); $("#save").click(function(){ $.ajax({ type:"POST", url:"serverjson.php", dataType:"json", data:{ name:$("#username").val(), number:$("#user_id").val(), sex:$("#usersex").val(), job:$("#userjob").val() }, //数据,连同请求发送到服务器中,主要用于POST success: function(data){ if(data.success){ $("#create").html(data.msg); } else{ $("#create").html("fault happened " + data.msg); } }, error:function(jqXHR){ $("#create").html("fault happened " + jqXHR.status); }, }); });});</script></body>
XHR2
下面介绍XHR2新定义的几个特性。
FormData
XHR2定义了FormData类型来封装表单数据的序列化。
var data = new FormData();data.append("name","Nicholas");
这段代码创建了一个FormData对象,并向其中添加了一些数据,append()方法接受2个参数,分别对应表单字段的名字和字段包含的值。
我们还可以直接向FormData构造函数传入表单元素。
var data = new FormData(document.forms[0]);
还可以直接将FormData对象实例传给send(),这样就可以不必明确地在XHR对象上设置请求头部,因为XHR对象可以识别传入的数据是FormData的实例,相应地配置适当的头部信息。
xhr.open("post","server.php");var form = document.getElementById("user-info");xhr.send(new FormData(form));
超时限定
XHR对象有一个timeout属性,表示请求在等待响应多少毫秒之后就终止。在send之前,我们可以给timeout赋值,如果在规定的时间之内,还未有响应返回,就会触发timeout事件,调用ontimeout事件处理程序。
var xhr = createXHR();xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ try{ //处理代码 } catch(ex){ //假设由ontimeout事件处理程序处理 } }};xhr.open("get","server.php");xhr.timeout = 1000; //1s(IE8+)xhr.ontimeout = function(){ alert("request did not return in a second!");}xhr.send();
但是有一个小问题,就是说如果在1s时,请求还没有返回,就会自动终止请求,同时会调用ontimeout事件处理程序,但此时有可能readyState属性值已经变成了4,就会调用onreadystatechange事件处理程序,可是,如果在终止请求后访问status属性就会报错。所以我们通常将检查status属性的代码封装到一个try-catch块内。
overrideMimeType()
该方法用于重写XHR响应的MIME类型。
进度事件
总共6个进度事件。
**每个请求都从触发loadstart事件开始,接着是一个或多个progress事件,然后触发error,abort,load事件中的一个,最后以触发loadend事件结束**。
提一下progress事件。onprogress事件处理程序会接收到一个event对象,其target属性是对应的XHR对象,但是包含着3个额外的属性,lengthComputable,position,totalSize。其中lengthComputable是一个表示进度信息是否可用的布尔值,position表示已经接收到的字节数,totalSize表示根据Content-length响应头部确定的预期字节数。
根据上面这些,我们可以为一个用户创建一个进度指示器。
xhr.onprogress = function(event){ var divStatus = document.getElementById("status"); if(event.lengthComputable){ divStatus.innerHTML = "Received " + event.position + " of " + event.totalSize + " bytes"; }};
跨域
不同域之间相互请求资源叫做跨域。
http://[协议]www[子域名].abc.com[主域名]:8080[端口号]/scipts/jquery.js[请求资源地址]
当协议,子域名,主域名,端口号任意一个不同时,都算作不同的域。
域名和域名对应ip间通信同样属于跨域。
代理
主要是通过后台实现,服务器改造,客户端代码不变,不属于前端范畴,在这里只提一下
jsonp
JSON with padding 填充式JSON或者参数式JSON
主要是利用在页面中创建script节点的方法向不同域提交HTTP请求的方法。
原理:script标签的src属性是没有跨域的限制的。
是被包含在函数调用中的JSON。由两部分组成:
jsonp由两部分组成,回调函数和数据。
- 回调函数:当响应到来时应该在页面中调用的函数。一般在请求中指定
- 数据:传入回调函数中的JSON数据
今天上午无意中看到一篇文章,叫说说JSON和JSONP,也许你会豁然开朗,觉得里面关于jsonp的那部分说得特别好,关于这个技术的产生和原理都说的很清晰,所以在这里特意来给自己的文章添上几笔。
首先要郑重声明:
jsonp不是ajax的一个特例。
jsonp的产生
- Ajax直接请求普通文件存在跨域无权限访问的问题;
- Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如script、img、iframe)
- 于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;
- 恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
- 这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
- 客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
- 为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
jsonp客户端的具体实现过程
1、我们知道,哪怕跨域js文件中的代码(当然指符合web脚本安全策略的),web页面也是可以无条件执行的。
远程服务器remoteserver.com根目录下有个remote.js文件代码如下:
alert('我是远程文件');
本地服务器localserver.com下有个jsonp.html页面代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script></head><body></body></html>
毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。
2、现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。
jsonp.html页面代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript"> var localHandler = function(data){ alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result); }; </script> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script></head><body></body></html>
remote.js文件代码如下:
localHandler({"result":"我是远程js带来的数据"});
运行之后查看结果,页面成功弹出提示窗口,显示本地函数被跨域的远程js调用成功,并且还接收到了远程js带来的数据。很欣喜,跨域远程获取数据的目的基本实现了,但是又一个问题出现了,我怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。
3、聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。
看jsonp.html页面的代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript"> // 得到航班信息查询结果后的回调函数 var flightHandler = function(data){ alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。'); }; // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码) var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler"; // 创建script标签,设置其属性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script标签加入head,此时调用开始 document.getElementsByTagName('head')[0].appendChild(script); </script></head><body></body></html>
这次的代码变化比较大,不再直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,本例中的重点也就在于如何完成jsonp调用的全过程。
我们看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
OK,服务器很聪明,这个叫做flightResult.aspx的页面生成了一段这样的代码提供给jsonp.html(服务端的实现这里就不演示了,与你选用的语言无关,说到底就是拼接字符串):
flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5});
我们看到,传递给flightHandler函数的是一个json,它描述了航班的基本信息。运行一下页面,成功弹出提示窗口,jsonp的执行全过程顺利完成!
4、到这里为止的话,相信你已经能够理解jsonp的客户端实现原理了吧?剩下的就是如何把代码封装一下,以便于与用户界面交互,从而实现多次和重复调用。
先前的例子:
function handleResponse(response){ alert("you're at ip address " + response.ip + ", which is in " + response.city + ", " + response.region_name);}var script = document.createElement("script");script.src = "http://freegeoip.net/json/?callback=handleResponse";document.body.insertBefore(script,document.body.firstChild);
jsonp的优势是能够直接访问响应文本,支持在浏览器和服务器之间的双向通信。不足的地方是jsonp方式只支持GET请求,不支持POST请求。
下面我们看一下在Jquery中用jsonp的代码,仍旧是上面那个例子
<body><!-- 和上面一样 --><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script><script>$(document).ready(function(){ $("#search").click(function(){ $.ajax({ type:"GET", url:"http://121.195.170.175:8077/ajaxdemo/serverjsonp.php?number="+$("#userid").val(), dataType:"jsonp", //改动一 jsonp:"callback", //改动二 success: function(data){ if(data.success){ $("#result").html(data.msg); } else{ $("#result").html("fault happened " + data.msg); } }, error:function(jqXHR){ $("#result").html("fault happened " + jqXHR.status); }, }); }); //save 点击响应部分});</script></body>
这只是前端部分的代码,后台根据你使用的后台语言做出相应的改动。
所以说jsonp是需要服务器端的页面进行相应的配合的。
CORS
CORS的基本思想是:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是应该失败。
实现此功能非常简单,只需由服务器发送一个响应标头即可。
在服务器做一个简单的改动,这是在php中的代码
header('Access-Control-Allow-Origin:*'); /指定跨域的域名
设置之后我们可以在调试工具中查看header是否已经设置成功。
但是CORS要求服务器首先要具备对CORS支持,这样浏览器才能对该服务器进行跨源访问。
这里要提一下,IE中引入XDR(XDomainRequest)来实现跨域安全通信,其余浏览器仍然是XHR对象。随着html5概念的出现,在原有XHR对象上提出了XHR2,XHR2中很好地支持了CORS。
下面是XDR和XHR的几个不同点:
- cookie不会随请求发送,也不会随响应返回。
- 只能设置请求头部信息中的Content-Type字段
- 不能访问响应头部信息
- 只支持GET和POST请求
### document.domain跨子域
只适用于不同子域的框架间的交互。
不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的。
<script type="text/javascript"> function test(){ var iframe = document.getElementById('ifame'); var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的 var doc = win.document;//这里获取不到iframe里的document对象 var name = win.name;//这里同样获取不到window对象的name属性 }</script><iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html 和 http://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。
1.在页面 http://www.example.com/a.html 中设置document.domain:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe><script type="text/javascript"> document.domain = 'example.com';//设置成主域 function test(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象 }</script>
2.在页面 http://example.com/b.html 中也设置document.domain:
<script type="text/javascript"> document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同</script>
使用html5的新方法 window.postMessage()
postMessage(data,origin)接受两个参数,data为要传递的数据,origin为目标窗口的源,包括协议+主机+端口([url]),其中url会被忽略,所以可以不写。
Comet
与Ajax不同,Comet是一种服务器向页面推送数据的技术。它能使信息近乎实时地被推送到页面上。
有两种实现Comet的方式:长轮询和流。
长轮询是短轮询的一个翻版。长轮询是页面发起一个到服务器的请求,然后服务器一直保持打开,直到有数据可以发送。发送完数据后浏览器关闭连接,随即又发送一个新的请求。这一过程在页面打开期间一直持续不断。
HTTP流不同于轮询,它在页面的整个生命周期内只使用一个HTTP连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
服务器发送事件SSE
SSE【Server-Sent Events】是围绕只读Comet交互推出的API或者模式。
创建到服务器的单向连接,服务器通过这个连接可发送任意数量的数据。服务器响应的类型不许是text/event-stream。SSE支持短轮询,长轮询和HTTP流,能在断开连接时自动确定何时重新连接。
var source = new EventSource("server.php");source.onmessage=function(event){ document.getElementById("result").innerHTML+=event.data + "<br />"; }; source.close();
Web Sockets
html5中的新规范。它可以在一个单独的连接上提供全双工,双向的通信。
直接看代码。
var socket = new WebSocket("ws://www.example.com/server.php"); //必须给构造函数传入绝对url,websockets不适用同源策略。socket.send("hello world!");socket.onmessage = function(event){ var data = event.data; //处理数据};socket.onopen = function(){ alert("connection established!");};socket.onerror = function(){ alert("connection error!");};socket.onclose = function(){ alert("connection close!");};socket.close(); //关闭连接
上面那段代码基本上涵盖了有关websocket的常用的方法。
下面我们说说其中的一些细节。
- websocket只能通过连接发送纯文本数据,如代码中的Hello world!字符串,因此,对于复杂的数据结构,在通过连接发送之前,必须经过序列化。此时,json又派上了大用场。我们可以利用将数据序列化为一个Json字符串,再send。与send一样,onmessage中的event对象有一个data属性,也是字符串,如果想得到其他格式的数据,需要解析他们。
- 代码中的几个事件,只有close事件的event对象有额外的信息。该event有三个额外的属性:wasClean,code,reason。wasClean是一个布尔值,表示连接是否已经明确关闭,code是服务器返回的数值状态码,而reason是一个字符串,包含服务器返回的信息。我们可以读取这些信息反馈给用户看。
关于跨域,还在学习中,如果上面我所说的有错误,欢迎指正。
- 初始ajax和跨域
- AJAX初始的开发框架
- 初始 Ajax----小例----javascript
- JAVA AJAX教程第一章-初始AJAX
- 初始Window和WindowManager
- webpack安装和初始
- js--ajax和跨域
- Ajax跨域和JSONP
- js--ajax和跨域
- Ajax和跨域请求
- ISAKMP - 解释域(DOI)和初始向量(IV)
- informix安装和初始配置
- windows8 初始界面和功能
- ArryList初始状态和扩容
- 位域初始
- 初始
- 初始
- 初始
- 文本情感分析+python+正面和负面新闻+新浪微博+情感字典+机器学习
- 不得不看的Java代码性能优化总结
- Educational Codeforces Round 20 Maximal Binary Matrix
- HashMap源码分析
- 链表3:反转链表
- 初始ajax和跨域
- 树状数组 or 归并树 —— HDU 4417
- C# 人脸识别
- 跟小刀学 数据结构 双向链表
- RabbitMQ,ActiveMq,ZeroMq比较
- reactnative Navigator api解释
- HDU3709
- PL2303在win10无法使用的解决办法
- 消息队列比较以及通信问题