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服務必須是安全可信的。