1. 程式人生 > >跨域請求的常用方式及解釋

跨域請求的常用方式及解釋

指定 strong json2 提交 能力 路徑 消息 string 動態

同源策略

首先基於安全的原因,瀏覽器是存在同源策略這個機制的,同源策略阻止從一個域加載的腳本去獲取另一個域上的文檔屬性。也就是說,受到請求的 URL 的域必須與當前 Web 頁面的域相同。這意味著瀏覽器隔離來自不同源的內容,以防止它們之間的操作。

js跨域是指通過js在不同的域之間進行數據傳輸或通信,比如用ajax向一個不同的域請求數據,或者通過js獲取頁面中不同域的框架中(iframe)的數據。

只要協議、域名、端口有任何一個不同,都被當作是不同的域。

下面介紹幾種常用的跨域請求方式

默認端口為:8080

一、利用jQuery獲取jsonp

JSONP的原理與實現思路

1)Web頁面調用js文件,可跨域。擴展:但凡有src屬性的標簽都具有跨域能力。


2)跨域服務器 動態生成數據 並存入js文件(通常json後綴),供客戶端調用。
3)為了便於客戶端使用數據,形成一個非正式傳輸協議,稱為JSONP。該協議重點是允許用戶傳遞一個callback參數給服務器,然後服務器返回數據時 將此callback參數作為函數名包裹住JSON數據,使得客戶端可以隨意定制自己的函數來自動處理返回數據。

1.1如果我們不用跨域請求的寫法的話:

$(‘#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;
        
    }

技術分享圖片

1.3jsonpCallback

為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方式了,那就請求不了了。

二、設置CORS頭“Access-Control-Allow-Origin”

  • CORS的原理:
CORS定義一種跨域訪問的機制,可以讓AJAX實現跨域訪問。CORS 允許一個域上的網絡應用向另一個域提交跨域 AJAX 請求。實現此功能非常簡單,只需由服務器發送一個響應標頭即可。
$(‘#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;
    }

技術分享圖片

三、iframe+window.postMessage實現跨域

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>

有幾個重要屬性

  1. origin:發送消息窗口的源(協議+主機+端口號)
  2. data:顧名思義,是傳遞來的message
  3. source:發送消息的窗口對象

這樣就可以接收跨域的消息了,我們還可以發送消息回去。

跨域請求的常用方式及解釋