首先基於安全的緣由,瀏覽器是存在同源策略這個機制的,同源策略阻止從一個域加載的腳本去獲取另外一個域上的文檔屬性。也就是說,受到請求的 URL 的域必須與當前 Web 頁面的域相同。這意味着瀏覽器隔離來自不一樣源的內容,以防止它們之間的操做。html
js跨域是指經過js在不一樣的域之間進行數據傳輸或通訊,好比用ajax向一個不一樣的域請求數據,或者經過js獲取頁面中不一樣域的框架中(iframe)的數據。前端
只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域。html5
默認端口爲:8080jquery
1)Web頁面調用js文件,可跨域。擴展:但凡是有src屬性的標籤都具備跨域能力。
2)跨域服務器 動態生成數據 並存入js文件(一般json後綴),供客戶端調用。
3)爲了便於客戶端使用數據,造成一個非正式傳輸協議,稱爲JSONP。該協議重點是容許用戶傳遞一個callback參數給服務器,而後服務器返回數據時 將此callback參數做爲函數名包裹住JSON數據,使得客戶端能夠隨意定製本身的函數來自動處理返回數據。ajax
1.1若是咱們不用跨域請求的寫法的話:json
$('#cors1').click(function () { $.ajax({ type:'get', url:'http://localhost:8081/girl/hello/say', success:function (data) { console.log(data); } }) });
1.2使用跨越請求的寫法,最簡單的就是設置dataType:jsonp:後端
jsonp指定服務器返回的數據類型爲jsonp格式,能夠看發起的請求路徑,自動帶了一個callback=xxx,xxx是jquery隨機生成的一個回調函數名稱。跨域
這裏的success默認success()做爲回調函數。數據返回到前端後,就是success(result)的形式,由於是script腳本,因此自動調用success函數,而result就是success的參數。瀏覽器
$('#cors1').click(function () { $.ajax({ type:'get', dataType: 'jsonp', url:'http://localhost:8081/girl/hello/say', success:function (data) { console.log(data); } }) });
@RequestMapping(value="/say", method = RequestMethod.GET) //後端代碼 public String say(@RequestParam("callback") String callback){ //callback前端傳過來的回調函數名稱 //數據 String result = "{age:22}"; //用回調函數名稱包裹返回數據,這樣,返回數據就做爲回調函數的參數傳回去了 result = callback + "(" + result + ")"; return result; }
爲jsonp請求指定一個回調函數名。這個值將用來取代jQuery自動生成的隨機函數名。安全
調用回調函數的時候,先調用了指定的showData,而後再調用了success。
$('#cors1').click(function () { $.ajax({ type:'get', dataType: 'jsonp', //指定服務器返回的數據類型 jsonpCallback: 'showData', //指定回調函數名稱 url:'http://localhost:8081/girl/hello/say', success:function (data) { console.log(data); } }) }); function showData(data) { console.log("show"+data); }
1.4jsonp
在一個jsonp請求中重寫回調函數的名字。這個值用來替代在"callback=?"這種GET或POST請求中URL參數裏的"callback"部分,好比{jsonp:'onJsonPLoad'}會致使將"onJsonPLoad=?"傳給服務器。
$('#cors1').click(function () { $.ajax({ type:'get', dataType: 'jsonp', jsonpCallback: 'showData', jsonp: 'sendParam', //指定參數名稱 url:'http://localhost:8081/girl/hello/say', success:function (data) { console.log(data); } }) }); function showData(data) { console.log(data); }
指定jsonp後,後端也要改變:
@RequestMapping(value="/say", method = RequestMethod.GET) public String say(@RequestParam("sendParam") String sendParam){ //sendParam前端傳過來的回調函數名稱 //數據 String result = "{age:22}"; //用回調函數名稱包裹返回數據,這樣,返回數據就做爲回調函數的參數傳回去了 result = sendParam + "(" + result + ")"; return result; }
1.5jsonp方式不支持POST方式跨域請求,就算指定成POST方式,會自動轉爲GET方式;然後端若是設置成POST方式了,那就請求不了了。
$('#cors1').click(function () { $.ajax({ type:'get', url:'http://localhost:8081/girl/hello/say', success:function (data) { console.log(data); } }) });
@RequestMapping(value="/say", method = RequestMethod.GET) public String say(HttpServletRequest request, HttpServletResponse response){ //設置響應頭 response.setHeader("Access-Control-Allow-Origin","*"); //當前我設置的header爲「*」,任意一個請求過來以後服務端咱們均可以進行處理&響應
// 指定特定域名能夠訪問
response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/")
//數據 String result = "{age:22}"; return result; }
script、image、iframe的src都不受同源策略的影響。因此咱們能夠藉助這一特色,實現跨域。
postMessage()方法容許來自不一樣源的腳本採用異步方式進行有限的通訊,能夠實現跨文本檔、多窗口、跨域消息傳遞。
發送消息
postMessage(data,origin)方法接受兩個參數
1.data:要傳遞的數據,html5規範中提到該參數能夠是JavaScript的任意基本類型或可複製的對象,然而並非全部瀏覽器都作到了這點兒,部分瀏覽器只能處理字符串參數,因此咱們在傳遞參數的時候須要使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js能夠實現相似效果。
2.origin:字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略,因此能夠不寫,這個參數是爲了安全考慮,postMessage()方法只會將message傳遞給指定窗口,固然若是願意也能夠建參數設置爲"*",這樣能夠傳遞給任意窗口,若是要指定和當前窗口同源的話設置爲"/"。
<iframe id="ifr" src="http://localhost:8081/girl/b.html"></iframe>
window.onload = function () { var ifr = document.getElementById("ifr"); ifr.contentWindow.postMessage("crsf","http://localhost:8081"); };
接收消息
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>testb</title> </head> <body> <div>b</div> </body> </html> <script>
window.addEventListener('message', function(event){
console.log('origin: '+event.origin); //origin: http://localhost:8080
console.log('data: '+event.data); //data: crsf
console.log(event.source);
// 回發數據
event.source.postMessage('hello world', event.origin);
});
</script>
有幾個重要屬性
這樣就能夠接收跨域的消息了,咱們還能夠發送消息回去。