前言:javascript
爲儘量保證瀏覽器端安全,瀏覽器會遵循SOP協議,即同源協議php
ajax沒法完成跨域請求html
$.get $.post $.ajax都不能夠前端
jsonp做爲ajax的一種擴展協議能夠完成跨域請求java
$.getJson()也能夠完成跨域請求(固然不跨域也能夠)jquery
平常開發中會常常遇到前端跨域訪問請求數據的場景ajax
好比json
www.server.com img.server.com
當用戶在www下瀏覽時須要獲取指定記錄id的圖片,則咱們須要在www的域下請求img域下的數據,常規狀況下瀏覽器會處於安全控制限制沒法完成跨域請求,但頁面中的script或iframe標籤是能夠載入跨域請求的(link img也能夠)後端
實現方式:跨域
===============================================================
看網上不少講跨域的都只是說了下前端如何編碼,對後端的處理隻字未提,雖而後端的處理很簡單,但後端的處理纔是點睛之筆,返回一個前端的調用函數語句,這就是傳說中的回調函數
<?php if (isset($_GET['callback'])) { $callback = $_GET['callback']; $resultArr = []; $resultArr['id'] = $_GET['id']; $resultArr['img'] = "http://img.server.com/upload/img/201511031319.png"; $resultJson = json_encode($resultArr); //callback({id:1, img:....}) 組裝成調用js函數的格式 客戶端載入天然觸發其本地定義的回調函數 echo $callback . "({$resultJson})"; exit(); } //由於是被script標籤請求載入的,因此返回的數據會包在script中,天然就觸發了callback函數
===============================================================
其實原理很簡單
一、在當前域下我定義一個函數做爲回調函數
二、組建一個script標籤元素節點,設置src爲跨域請求的某API的url地址,同時此url地址中務必填寫上回調函數名參數
三、將script標籤掛載到文檔流中,會跨域請求載入,變相的訪問了跨域API,觸發了API的方法,返回的數據被填充到script標籤中,若是返回的是一個當前域下定義好的函數,那天然就觸發處理相關數據了
四、跨域完成
在www下定義回調函數callback
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> <script type="text/javascript" src="http://www.yii.com/a.js"></script> </head> <body> <button onclick="request()">click here</button> <script type="text/javascript"> //回調函數callback定義 //服務端輸出的數據爲 callback({key1:data1, key2;data2}) 到本頁面 即調用此定義好的函數 function callback(json) { for (i in json) { alert(i + ":" + json[i]); } if (json.tagId) { var tagId = document.getElementById(json.tagId); tagId.parentNode.removeChild(tagId); } } //發起跨域請求 function request() { //利用script標籤可跨域訪問的特性 var script = document.createElement('script'); script.id = Math.random(); script.type = 'text/javascript'; //跨域 將callback函數名稱傳遞給跨域服務器 服務端利用此函數名組建 script.src = "http://img.server.com/index.php?callback=callback&id=1&tagId=" + script.id; //將可跨域請求的script標籤掛載到head標籤上 document.getElementsByTagName("head")[0].appendChild(script); } </script> </body> </html>
===============================================================
jsonp是ajax的擴展,嚴格的說它已經不是ajax,只是複用ajax的某些控制流程,封裝咱們上面說的js方式
重點:
dataType:'jsonp' //指定使用jsonp方式
jsonp:'callback' //回調函數的鍵名 傳遞給服務器時服務器經過此鍵名獲取應該返回調用的函數名
jsonpCallback:'myCallback' //回調函數名不隨機,自定義一個
<script type="text/javascript" > //其實jquery會組合成這樣的請求 //http://img.server.com/index.php?callback=myCallback&id=1 $.ajax({ async: false, type: 'get', url: "http://img.server.com/index.php?id=1", //指定爲jsonp方式 dataType: 'jsonp', //回調函數的鍵值名,即服務端經過此鍵值訪問傳遞的回調函數名 jsonp: 'callback', //回調函數名,若不指定則jquery會隨機生成一個 jsonpCallback: 'myCallback', success: function(result) { for (var i in result) { alert(i + ":" + result[i]); } }, timeout: 3000 }); //Jquery會根據你指定的jsonpCallback參數在本地生成一個 //function myCallback(result) { //這樣就調用了success方法 //this.success(result); //} </script>
===============================================================
重點:
必定要在url中寫上callback=?,只有這樣纔會在本地生成一個回調函數,跨域的後端經過callback獲取到此函數名,進行回調
<script type="text/javascript" > //其實jquery會組合成這樣的請求 //http://img.server.com/index.php?callback=myCallback&id=1 var url = "http://img.server.com/index.php?callback=?"; //記住必定要有callback=? var data = {'id':1}; $.getJSON( url, data, function(result){ for (var i in result) { alert(i + ":" + result[i]); } }); </script>
===============================================================