什么是跨域?解決跨域的六種方法。


一、什么是跨域?

跨域,指的是瀏覽器不能執行其他網站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制。

所謂同源是指,域名,協議,端口均相同,不明白沒關系,舉個例子:

http://www.123.com/index.html 調用 http://www.123.com/server.PHP (非跨域)

http://www.123.com/index.html 調用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 調用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 調用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 調用 https://www.123.com/server.php (協議不同:http/https,跨域)

請注意:localhost和127.0.0.1雖然都指向本機,但也屬於跨域。

瀏覽器執行javascript腳本時,會檢查這個腳本屬於哪個頁面,如果不是同源頁面,就不會被執行。

你可以理解為兩個域名之間不能跨過域名來發送請求或者請求數據,否則就是不安全的,這種不安全也就是CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。

一張圖解釋什么是CSRF

 二、解決跨域6種辦法:

2.1 JSONP:

使用方式就不贅述了,但是要注意JSONP只支持GET請求,不支持POST請求。

2.2 代理:

例如www.123.com/index.html需要調用www.456.com/server.php,可以寫一個接口www.123.com/server.php,由這個接口在后端去調用www.456.com/server.php並拿到返回值,然后再返回給index.html,這就是一個代理的模式。相當於繞過了瀏覽器端,自然就不存在跨域問題。

2.3 PHP端修改header(XHR2方式)

在php接口腳本中加入以下兩句即可:

header('Access-Control-Allow-Origin:*');//允許所有來源訪問

header('Access-Control-Allow-Method:POST,GET');//允許訪問的方式

2.4 iframe

所以跨域通信其實很簡單,在iframe和主頁里都不斷地檢測hashtag有沒有變化,一旦有變化,就做出相應的改變。

setInterval(function() {
    var hashVal = window.location.hash.substr(1);
    document.body.style.backgroundColor = hashVal;
}, 1000); 

 這么做的問題就是,需要不斷地去檢測hashtag是否改變,效率有點低,如果能通過原生的監聽來實現,就會更加高效和優雅。這里就涉及到另一個iframe特性:可以設置其他iframe的大小,即使是不同域的。而頁面的resize事件是可以監聽的,所以就有了下面這個模型。

主頁面先把消息附加到hashtag,然后改變一個隱藏的(或者頁面外的)iframe的size。這個iframe會監聽resize事件,同時捕獲到hashtag。捕獲到hashtag后(也就是所需的數據),再對hashtag做進一步的處理。處理完后把數據傳到主頁內的一個iframe,或者直接操作該iframe。這樣就比較優雅地完成了跨域操作。

Demo

將以下代碼拷貝到本地的一個html文件,然后雙擊在瀏覽器中打開,看看能不能查單詞。(ajax無法跨協議,這是iframe比ajax強大的地方)

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script>
            $(function(){
                $('#btn').click(function(){
                    $proxy = $('#proxy');
                    var src = $proxy.attr('src').split('#')[0];
                    $proxy.attr('src', src + '#' + $('input[name=it]').val());
                    $proxy.css('width', $proxy.width()+1+'px');
                });
            });
        </script>
    </head>
    <body>

        <input type="text" name="it"> <button id="btn">Translate</button>
        <p></p>
        <iframe src="http://demo.leezhong.com/crossdomain/proxy.html" name="proxy" id="proxy" style="position:absolute; top:-10px; width:1px; height:1px"></iframe>
        <iframe src="http://demo.leezhong.com/crossdomain/show.html" name="show" id="show" style="width:60%;height:300px"></iframe>
    </body>
</html>

2.5 通過 window.name 實現跨域

這篇文章是對 JavaScript跨域總結與解決辦法 的補充。

有三個頁面:

  • a.com/app.html:應用頁面。
  • a.com/proxy.html:代理文件,一般是一個沒有任何內容的html文件,需要和應用頁面在同一域下。
  • b.com/data.html:應用頁面需要獲取數據的頁面,可稱為數據頁面。

實現起來基本步驟如下:

1、在應用頁面(a.com/app.html)中創建一個iframe,把其src指向數據頁面(b.com/data.html)。
數據頁面會把數據附加到這個iframe的window.name上,data.html代碼如下:

<script type="text/javascript">
    window.name = 'I was there!';    // 這里是要傳輸的數據,大小一般為2M,IE和firefox下可以大至32M左右
                                     // 數據格式可以自定義,如json、字符串
</script>

 2、在應用頁面(a.com/app.html)中監聽iframe的onload事件,在此事件中設置這個iframe的src指向本地域的代理文件(代理文件和應用頁面在同一域下,所以可以相互通信)。app.html部分代碼如下:

<script type="text/javascript">
    var state = 0, 
    iframe = document.createElement('iframe'),
    loadfn = function() {
        if (state === 1) {
            var data = iframe.contentWindow.name;    // 讀取數據
            alert(data);    //彈出'I was there!'
        } else if (state === 0) {
            state = 1;
            iframe.contentWindow.location = "http://a.com/proxy.html";    // 設置的代理文件
        }  
    };
    iframe.src = 'http://b.com/data.html';
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadfn);
    } else {
        iframe.onload  = loadfn;
    }
    document.body.appendChild(iframe);
</script>

3、獲取數據以后銷毀這個iframe,釋放內存;這也保證了安全(不被其他域frame js訪問)。

<script type="text/javascript">
    iframe.contentWindow.document.write('');
    iframe.contentWindow.close();
    document.body.removeChild(iframe);
</script>

總結起來即:iframe的src屬性由外域轉向本地域,跨域數據即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。

2.6 HTML5中最炫酷的API之一(window.postMessage)

就是  跨文檔消息傳輸Cross Document Messaging。高級瀏覽器Internet Explorer 8+, chrome,Firefox , Opera  和 Safari 都將支持這個功能。這個功能實現也非常簡單主要包括接受信息的”message”事件和發送消息的”postMessage”方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM