AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种建立交互式网页应用的网页开发技术。javascript
AJAX 的出现使得网页能够经过在后台与服务器进行少许数据交换,实现网页的局部刷新。php
可是出于安全的考虑,ajax不容许跨域通讯(浏览器同源策略)。
若是尝试从不一样的域请求数据,就会出现错误(跨域错误)。
在实际开发中,每每须要进行跨于请求,这时要怎么办呢?css
一、Ajax为何不能跨域?究竟是卡在哪一个环节了?。 (请求成功了,但客户端浏览器拿不到请求结果)html
Ajax其实就是向服务器发送一个GET或POST请求,而后取得服务器响应结果,返回客户端。 理论上这是没有任何问题的,然而普通ajax跨域请求,在服务器端不会有任何问题,只是服务端响应数据返回给浏览器的时候, 浏览器根据响应头的Access-Control-Allow-Origin字段的值来判断是否有权限获取数据, 通常状况下,服务器端若是没有在这个字段作特殊处理的话,跨域是没有权限访问的,因此响应数据被浏览器给拦截了, 因此在ajax回调函数里是获取不到数据的。因此如今ajax跨域的问题能够转化为数据怎么拿回客户端的问题。
二、 html的script标签,img标签,iframe标签,能够请求第三方的资源(不受同源策略影响)前端
web页面能够加载放在任意站点的js、css、图片等资源,不会受到"跨域"的影响。 这个时候,咱们会想到:既然咱们能够调用第三方站点的js,那么若是咱们将数据放到第三方站点的js中不就能够将数据带到客户端了吗?
一、什么是JSONP?html5
JSONP(JSON with Padding(填充))是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。 其核心思想是利用JS标签里面的跨域特性进行跨域数据访问, 在JS标签里面存在的是一个跨域的URL,实际执行的时候经过这个URL得到一段字符串, 这段返回的字符串必须是一个合法的JS调用,经过EVAL这个字符串来完成对得到的数据的处理。 即: <script src='url'></script> JSONP是一个非官方的协议,它容许在服务器端集成Script tags返回至客户端, 经过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
二、JSONP的粗糙实现java
下面咱们经过一个例子来讲明一下JSONP是如何实现ajax跨域请求的。mysql
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>jsonp</div> </body> <script> function getremotedata(data) { console.log(data); } var div = document.getElementsByTagName('div'); div[0].onclick = function(){ var url = "./getdata.js"; var script = document.createElement('script'); script.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(script); }; </script> </html>
getremotedata({ code:0, result:'success' });
获得的结果:jquery
html代码仍是和上面同样,只要改变 url就能够了 url= 'localhsot:8080/search.php?callback=getremotedata'
git
后台 php 代码
<?php $callback = $_GET['callback']; if($callback == 'getremotedata' ){ echo $_GET['$callback']).'('. json_encode({code:0,msg:"success"}) .')'; } ?>
看到这里清楚了吧,就是第三方站点生成一个对回调函数的调用,传入查询结果,
而后经过 <script>
加载到客户端执行
下图是 jsonp请求的流程图
jquery 是如何把 jsonp 封装到ajax里面的?
<script type="text/javascript"> function GetAjaxData() { $.ajax({ type: "get", async: false, url: "http://localhost:8080/getdata.php", dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,标识jsonp回调函数名(通常为:callback) jsonpCallback: "GetData",//callback的function名称 success: function (data) { console.log(data); }, error: function () { alert('fail'); } }); } </script>
通常状况下jqury 生成的访问 远程站点的 url
默认状况下:(我所在的实际项目中的使用)
http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=jQuery191028614189839964865_1497261919344&token=420171c8-031a58667e64&_=1497261919346
上述代码请求生成的url(设置 jsonpCallback
的值为 GetData
)
http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=GetData&token=420171c8-00b8-031a58667e64&_=1497261919346
最后 一个 _=1497261919346
k v 是为了防止浏览器缓存,而由 jquery 自动增长上的。
因此至关于 在 前端文件中引入了 一个这样的js文件
<script src="http://web.k3k.net/haila3/pt/tp/index.php/Home/User/getusergoto/?callback=GetData&token=420171c8-00b8-031a58667e64&_=1497261919346"></script>
这里有2个重要的参数
jsonp
:
在一个jsonp请求中重写回调函数的名字。这个值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,
好比{jsonp:'onJsonPLoad'}会致使将"onJsonPLoad=?"传给服务器。
jsonpCallback
:
为jsonp请求指定一个回调函数名。这个值将用来取代jQuery自动生成的随机函数名。
这主要用来让jQuery生成一个独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。
你也能够在想让浏览器缓存GET请求的时候,指定这个回调函数名。
从jQuery 1.5开始,你也可使用一个函数做为该参数设置,在这种状况下,该函数的返回值就是jsonpCallback的结果。
经过一开始
jsonp
原理的分析,能够得出:
当咱们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据。
而咱们使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码
因此咱们可见服务器代码最后一行
echo $_GET['$callback']).'('. json_encode({code:0,msg:"success"}) .')';
就是执行的 getdata
,而后把数据经过回调的方式传递过去
OK,就是整个流程就是:
客户端发送一个请求,规定一个可执行的函数名
(这里就是jQuery作了封装的处理,自动帮你生成回调函数并把数据取出来供success属性方法来调用,不是传递的一个回调句柄),
服务端接受了这个 getdata
函数名,而后把数据经过实参的形式发送出去
以上是 jquery 封装的 ajax方法里面的
jsonp
请求,说来讲去,本身都好像忘记了普通的ajax
请求
//1.建立对象 var ajax = ''; if(window.XMLHttpRequest){ ajax = new XMLHttpRequest(); /* 现代浏览器 */ }else if(window.ActiveXObject){ ajax = new ActiveXObject("Microsoft.XMLHTTP"); /* 万恶的ie浏览器 */ } //2.建立请求 //get请求方法(拼接url参数) // var url="login.php?name="+name+"&password="+pass; // ajax.open("GET",url,true); //post请求 ajax.open("POST","login.php",true); ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var data="name="+name+"&password="+pass; //3.发送请求 // ajax.send(); //get 方式发送请求 ajax.send(data); //post 方式发送请求 //4.捕获请求状态、onreadystatechange表示当前请求状态 ajax.onreadystatechange=function(){ //5.判断请求状态 if(ajax.readyState==4){ //6.判断请求结果 if(ajax.status==200){ //请求成功将结果 responseText 放入回调函数中 succ(ajax.responseText); } } }
注意
经过检测window对象是否有XMLHttpRequest属性来肯定浏览器是否支持标准的XMLHttpRequest。
注意,不要根据浏览器的navigator.userAgent来检测浏览器是否支持某个JavaScript特性,一是由于这个字符串自己能够伪造,二是经过IE版本判断JavaScript特性将很是复杂。
当建立了XMLHttpRequest对象后,要先设置onreadystatechange的回调函数。在回调函数中,一般咱们只需经过readyState === 4判断请求是否完成,
若是已完成,再根据status === 200判断是不是一个成功的响应。
XMLHttpRequest对象的open()方法有3个参数,
第一个参数指定是GET仍是POST,
第二个参数指定URL地址,
第三个参数指定是否使用异步,默认是true,因此不用写。
注意,千万不要把第三个参数指定为false,不然浏览器将中止响应,直到AJAX请求完成。
若是这个请求耗时10秒,那么10秒内你会发现浏览器处于“假死”状态。
最后调用send()方法才真正发送请求。
GET请求不须要参数,
POST请求须要把body部分以字符串或者FormData对象传进去。
<script type="text/javascript"> $("#btn").on("click",function(){ var name=$("#name").val(); var pass=$("#password").val(); $.ajax({ type:"post", url:"login&jq.php", async:true, //异步简写 dataType:"json", //转化为json类型 data:{ name:name, password:pass, }, success:function(data){ console.log(data); }, error:function(data){ alert(data); } }); }) </script>
后台 php 代码
<?php include_once "common.php"; $name=$_POST["name"]; $password=$_POST["password"]; $sql="select*from user where name='$name' and password= '$password'"; $result=mysql_query($sql); if(mysql_num_rows($result)==1){ $row = mysql_fetch_assoc($result); //只能传一个json echo json_encode($row); }else{ //只能用json echo '{"msg":"输入有误"}'; } ?>
固然实现跨域的方法还有不少,html5规范 的 CORS(全称Cross-Origin Resource Sharing),是HTML5规范定义的如何跨域访问资源。
了解CORS前,咱们先搞明白概念: Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com) 发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域, 若是是,则这次跨域请求成功,若是不是,则请求失败,JavaScript将没法获取到响应的任何数据。 假设本域是my.com,外域是sina.com,只要响应头Access-Control-Allow-Origin为http://my.com,或者是*,本次请求就能够成功。 可见,跨域可否成功,取决于对方服务器是否愿意给你设置一个正确的Access-Control-Allow-Origin,决定权始终在对方手中。
一、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也同样,都是请求一个url,而后把服务器返回的数据进行处理,所以jquery和ext等框架都把jsonp做为ajax的一种形式进行了封装;
二、ajax和jsonp其实本质上是不一样的东西。ajax的核心是经过XMLHttpRequest获取非本页内容,而jsonp的核心则是经过HTTP来动态添加 <script>
标签来调用服务器提供的js脚本。
三、其实ajax与jsonp的区别不在因而否跨域,ajax经过服务端代理(CORS)同样能够实现跨域,jsonp自己也不排斥同域的数据的获取。
四、jsonp是一种方式或者说非强制性协议,如同ajax同样,它也不必定非要用json格式来传递数据,若是你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
五、jsonp整个过程当中,本地站点一直处于主动的地位,主动的发送请求,主动的加载远程js.而第三方站点则处于被动的响应。
1.1它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP能够跨越同源策略; 1.2它的兼容性更好,在更加古老的浏览器中均可以运行,不须要XMLHttpRequest或ActiveX的支持; 1.3在请求完毕后能够经过调用callback的方式回传结果。 将回调方法的权限给了调用方。这个就至关于将controller层和view层终于分开了。 我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操做都由调用者来本身定义就行了。 若是有两个页面须要渲染同一份数据,大家只须要有不一样的渲染逻辑就能够了, 逻辑均可以使用同 一个jsonp服务。
2.1它只支持GET请求而不支持POST等其它类型的HTTP请求 2.2它只支持跨域HTTP请求这种状况,不能解决不一样域的两个页面之间如何进行JavaScript调用的问题。 2.3 jsonp在调用失败的时候不会返回各类HTTP状态码。 2.4缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。 那么结果是什么?全部调用这个 jsonp的网站都会存在漏洞。 因而没法把危险控制在一个域名下…因此在使用jsonp的时候必需要保证使用的jsonp服务必须是安全可信的。