JavaScript跨域


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

也就是“http://www.baidu.com”這個URL首部,必須完全一樣才能互相通信。

這個也叫同源策略,當前域名的js只能讀取/修改同域下的窗口屬性

為什么要有同源策略?為了防止CSRF攻擊,保證來至不同源的對象不會互相干擾。

一、通過jsonp跨域(實際上是動態創建script標簽)

原理:不同的域可以傳輸JS文件

服務器的data.php:

 
         
<?php
$callback=$_GET['callback'];//得到的回調函數名
$data=array('a','b','c');//需要返回的數據
echo $callback.'('.json_encode($data).')';//輸出
?>

本地的HTML:

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<script>
    function dosomething(jsondata){
        console.log(jsondata)
    }
</script>
<script src='http://www.a.com/data.php?callback=dosomething'></script>
</body>
</html>

或者用jquery:

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js"></script>  
</head>
<body>
<script>
$.getJSON("http://www.a.com/data.php?callback=?"function(jsondata) {
    console.log(jsondata);
});
</script>
</body>
</html>

結果:

["a","b","c"]

JSONP的優點是:1.它不像XMLHttpRequest對象實現的Ajax請求那樣受到同源策略的限制;

         2.它的兼容性更好,在更加古老的瀏覽器中都 可以運行,不需要XMLHttpRequest或ActiveX的支持;

        3.在請求完畢后可以通過調用callback的方式回傳結果。

JSONP的缺點是:1.它只支持GET請求而不支持POST等其它類型的HTTP請求;

        2.它只支持跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JS調用的問題。

        3.jsonp在調用失敗的時候不會返回各種HTTP狀態碼。

        4.安全性欠缺。

 

 

2、通過document.domain+ iframe (只有在主域相同的時候才能使用該方法)

兩個不同域的a.html和b.html

在www.a.com/a.html中:

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>a跨域</title> 
</head>
<body>
<script>
function onLoad(){
    var iframe=document.getElementById('iframe');
    var win=iframe.contentWindow;//能讀取iframe里的window對象
    var doc=win.document;//無法讀取,報錯
    var name=win.name;//無法讀取,報錯
}
</script>
<iframe id="iframe" src="http://www.a.com/b.html" onload="onLoad()"></iframe>
</body>
</html>

在www.script.a.com/b.html中:

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>b跨域</title>  
</head>
<body>
<div>內容</div>
</body>
</html>

解決辦法:在兩個頁面都插入document.domain,這樣就能訪問iframe里window對象的各種屬性。

 
         
<script>
    document.domain='a.com';//設置成主域
</script>

 

3、使用window.name來進行跨域

原理:在一個窗口(window)的生命周期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限

同一目錄下的a.html和b.html

a.html

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>a跨域</title> 
</head>
<body>
<script>
window.name='頁面a設置的值';
setTimeout(function(){
    window.location='b.html'
},3000);
</script>
</body>
</html>
 

b.html

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>b頁面</title> 
</head>
<body>
<script>
alert(window.name);
</script>
</body>
</html>

a.html頁面載入后3秒,跳轉到了b.html頁面,彈出“頁面a設置的值”

跨域:在b.html里設置window.name,a.html就能訪問這個值了(。。。我未成功)

 

4、使用HTML5的window.postMessage方法來跨域傳送數據

 不同域的a.html和b.html

a.html

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>a跨域</title> 
</head>
<body>
<script>
function onLoad(){
    var iframe=document.getElementById('iframe');
    var win=iframe.contentWindow;
    win.postMessage('來自a頁面的信息','*');//第二個參數為想訪問的域,*為通配
}
</script>
<iframe id="iframe" src="http://www.a.com/b.html" onload="onLoad()"></iframe>
</body>
</html>

b.html

 
         
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>b跨域</title> 
</head>
<body>
<script>
window.onmessage=function(e){
    e=e||event;
    alert(e.data);
}
</script>
</body>
</html>

 

5.利用flash

6.利用iframe和location.hash

7.利用CORS

CORS是自定義HTTP頭部,使瀏覽器和服務器對比,從而決定請求和響應是否應該進行

IE8使用XDR對象實現CORS,和XHR類似用法

var xdr=new XDomainRequest();
xdr.onload=function(){
alert(xdr.responseText)
};
xdr.open('get',"http://www.a.com/");
xdr.send(null)

現代瀏覽器使用普通的XMLHttpRequest對象請求就行。

 

8.圖像Ping

var img=newImage();
img.onload=img.onerror=function(){
alert('1');
};
img.src="http://www.a.com/test?name=aaa";

缺點:1.只能GET  2.無法訪問服務器的響應文本

 

前面這幾種方法,大部分都需要前后兩端支持。如果單純的前端實現跨域,可以使用代理。

1.https://github.com/hongrunhui/node-proxy(未測試過)

2.eezz.com (代理網站請求返回的數據有時候沒刷新,可能是請求頻率/次數受限制了?所以還是有點小問題)

 
         
  var requestUrl = "http://www.weather.com.cn/adat/sk/101110101.html";
  //這里一定要注意,實際請求的url其實是以參數形式從eezzo.com讀取的,因此我們都要對url進行編碼,使用encodeURI方法即可
  $.getJSON("http://eezzo.com/API/CD", { url: encodeURI(requestUrl) }, function(json) {
     console.log (json);
  });

3.雅虎代理,同上

<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script>
var requestURL="http://www.weather.com.cn/adat/sk/101110101.html";
$.getJSON("http://query.yahooapis.com/v1/public/yql", {
    q: "select * from json where url=\""+requestURL+"\""//請注意划線和兩個引號
    format: "json"
}, function(data) {
    if (data.query.results) {
        console.log(data.query.results.json);
    } else {
        console.log('no such code: ' + code);
    }
});
</script>

 

4.原生代碼實現jsonp跨域讀取(動態創建script)

    var jsonp = function (url, callback) {
        if (typeof url === 'undefined') {
            throw 'the 1st param "url" missing';
        }
        if (typeof callback === 'undefined') {
            throw 'the 2nd param "callback" missing';
        }
        var jsonpcallback = 'callback' + new Date().valueOf();
        if (typeof callback !== 'string') {
            window[jsonpcallback] = callback;
            callback = jsonpcallback;
        } else {
            window[jsonpcallback] = function (data) {
                eval(callback).call(window, data);
            }
        }
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', url + (url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + jsonpcallback);
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(script);
    };
 
    jsonp('https://api.douban.com/v2/movie/top250', function (data) {
        console.log(data);
    });

簡化版:

        var jsonp = (url, callback) => {
            var jsonpcallback = 'callback' + new Date().valueOf(); //隨便寫個字符串
            window[jsonpcallback] = callback; //再把傳進來的callback暴露到全局,命名為上面的字符串

            var script = document.createElement('script'); //創建標簽
            script.setAttribute('src', url + (url.indexOf('?') == -1 ? '?' : '&') + 'callback=' + jsonpcallback);
            document.getElementsByTagName('head')[0].appendChild(script); //標簽插入頭部
        };

 

5.設置dataType為jsonp

    $.ajax({
        url: "https://api.douban.com/v2/movie/top250",
        dataType: 'jsonp',
        success: function (data) {
            console.log(data);
        }
    });

 


免責聲明!

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



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