五月综合缴情婷婷六月,色94色欧美sute亚洲线路二,日韩制服国产精品一区,色噜噜一区二区三区,香港三级午夜理伦三级三

您現(xiàn)在的位置: 365建站網(wǎng) > 365文章 > 什么是跨域 怎么解決ajax/iframe跨域問題

什么是跨域 怎么解決ajax/iframe跨域問題

文章來源:365jz.com     點擊數(shù):898    更新時間:2017-11-26 14:39   參與評論

什么是跨域?

 

跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對javascript施加的安全限制。

所謂同源是指,域名,協(xié)議,端口均相同,不明白沒關(guān)系,舉個栗子:

http://theartemis.cn/index.html 調(diào)用 http://www.365jz.com/server.php (非跨域)

http://www.365jz.com/index.html 調(diào)用 http://www.365yanshi.com/server.php (主域名不同:365jz/365jz,跨域)

http://abc.365jz.com/index.html 調(diào)用 http://def.365jz.com/server.php (子域名不同:abc/def,跨域)

http://theartemis.cn:8080/index.html 調(diào)用 http://www.365jz.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.365jz.com/index.html 調(diào)用 https://www.365jz.com/server.php (協(xié)議不同:http/https,跨域)

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

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

特別注意兩點:
第一,如果是協(xié)議和端口造成的跨域問題“前臺”是無能為力的,
第二:在跨域問題上,域僅僅是通過“URL的首部”來識別而不會去嘗試判斷相同的ip地址對應(yīng)著兩個域或兩個域是否在同一個ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解為“Domains, protocols and ports must match”。

解決辦法:

1、JSONP:

jsonp 全稱是JSON with Padding,是為了解決跨域請求資源而產(chǎn)生的解決方案,是一種依靠開發(fā)人員創(chuàng)造出的一種非官方跨域數(shù)據(jù)交互協(xié)議。

一個是描述信息的格式,一個是信息傳遞雙方約定的方法。

jsonp的產(chǎn)生:

1.AJAX直接請求普通文件存在跨域無權(quán)限訪問的問題,不管是靜態(tài)頁面也好.

2.不過我們在調(diào)用js文件的時候又不受跨域影響,比如引入jquery框架的,或者是調(diào)用相片的時候

3.凡是擁有scr這個屬性的標(biāo)簽都可以跨域例如<script><img><iframe>

4.如果想通過純web端跨域訪問數(shù)據(jù)只有一種可能,那就是把遠(yuǎn)程服務(wù)器上的數(shù)據(jù)裝進(jìn)js格式的文件里.

5.而json又是一個輕量級的數(shù)據(jù)格式,還被js原生支持

6.為了便于客戶端使用數(shù)據(jù),逐漸形成了一種非正式傳輸協(xié)議,人們把它稱作JSONP,該協(xié)議的一個要點就是允許用戶傳遞一個callback 參數(shù)給服務(wù)端

demo1:基于script標(biāo)簽實現(xiàn)跨域

舉個例子:我在http://365jz.com/json/jsonp/jsonp_2.html下請求一個遠(yuǎn)程的js文件

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
 
<script type="text/javascript">
    var message = function(data) {
        alert(data[1].title);
    };
</script>
 
<script type="text/javascript" src="http://web.cn/js/message.js"></script>
</head>
<body>
<div id='testdiv'></div>
</body>
</html>
 

遠(yuǎn)程的message.js文件是:

message([
     {"id":"1", "title":"天津新聞聯(lián)播,雷人搞笑的男主持人"},
     {"id":"2", "title":"樓市告別富得流油 專家:房價下跌是大概率事件"},
     {"id":"3", "title":"法國人關(guān)注時事 八成年輕人每天閱讀新聞"},
     {"id":"4", "title":"新聞中的歷史,歷史中的新聞"},
     {"id":"5", "title":"東陽新聞20140222"},
     {"id":"6", "title":"23個職能部門要增加新聞發(fā)布頻次"},
     {"id":"7", "title":"《貴州新聞聯(lián)播》 中國美麗鄉(xiāng)村"},
     {"id":"8", "title":"朝韓離散家屬團(tuán)聚首輪活動結(jié)束"},
     {"id":"9", "title":"索契冬奧會一天曝出兩例興奮劑事件"},
     {"id":"10", "title":"今天中國多地仍將出現(xiàn)中度霾"}
 ]);

這個時候我們得到的相應(yīng)頭是:

這樣就實現(xiàn)跨域成功了,因為服務(wù)端返回數(shù)據(jù)時會將這個callback參數(shù)(message)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動處理返回數(shù)據(jù)了
 

demo2:  基于jquery跨域

那么如何用jquery來實現(xiàn)我們的跨域呢???jquery已經(jīng)把跨域封裝到ajax上了,而且封裝得非常的好,使用起來也特別方便

jsonp形式的ajax請求:并且通過get請求的方式傳入?yún)?shù),注意:跨域請求是只能是get請求不能使用post請求

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    var name = 'chenshishuo';
    var sex = 'man';
    var address = 'shenzhen';
    var looks = 'handsome ';
     $.ajax({
         type : 'get',
         url:'http://192.168.31.137/train/test/testjsonp',
        data : {
            name : name,
            sex : sex,
            address : address,
            looks : looks,
        },
        cache :false,
        jsonp: "callback",
        jsonpCallback:"success",
        dataType : 'jsonp',
        success:function(data){
            alert(data);
        },
        error:function(data){
            alert('error');
        }        
    });
});
</script>
</head>
<body>
<input id='inputtest' value='546' name='inputtest'>
<div id='testdiv'></div>
</body>
</html>
jsonp 傳遞給請求處理程序或頁面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(默認(rèn)為:callback)
jsonpCallback 自定義的jsonp回調(diào)函數(shù)名稱,默認(rèn)為jQuery自動生成的隨機函數(shù)名

看看請求頭和相應(yīng)頭吧

請求頭:jquery會自動帶入callback參數(shù),當(dāng)服務(wù)端獲取到這個參數(shù)后,返回回來.(響應(yīng)頭)

現(xiàn)在是不是明白了跨域的基本原理,和基本的使用方法呢??

上面我們說到img中的src可以自動調(diào)用遠(yuǎn)程圖片的(這個比較簡單我在這里就不說了)

還有ifram請求:

基于iframe實現(xiàn)的跨域要求兩個域具有aa.xx.com,bb.xx.com 這種特點,

也就是兩個頁面必須屬于一個基礎(chǔ)域(例如都是xxx.com),使用同一協(xié)議和同一端口,這樣在兩個頁面中同時添加document.domain,就可以實現(xiàn)父頁面調(diào)用子頁面的函數(shù)

要點就是 :通過修改document.domain來跨子域
 

demo3: 通過iframe來跨子域

http://a.study.cn/a.html 請求 http://b.study.cn/b.html

在a.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
        <script type="text/javascript">
            document.domain = 'study.cn';
            function test() {
                alert(document.getElementById('a').contentWindow);
            }
        </script>
</head>
<body>
    <iframe id='a' src='http://b.study.cn/b.html' onload='test()'>
</body>
</html>

在b.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script type="text/javascript">
document.domain = 'study.cn';
</script>
</head>
<body>
    我是b.study.cn的body
</body>
</html>

 運行效果截圖:

我們就可以通過js訪問到iframe中的各種屬性和對象了

如果你想在http://a.study.cn/a.html頁面中通過ajax直接請求頁面http://b.study.cn/b.html,即使你設(shè)置了相同的document.domain也還是不行的.

所以修改document.domain的方法只適用于不同子域的框架(父類與子類)間的交互。

如果想通過使用ajax的方法去與不同子域間的數(shù)據(jù)交互或者是js調(diào)用,只有兩種方法,一種是使用jsonp的方法外,還有一種是使用iframe來做一個代理。

原理就是讓這個 iframe載入一個與你想要通過ajax獲取數(shù)據(jù)的目標(biāo)頁面處在相同的域的頁面,所以這個iframe中的頁面是可以正常使用ajax去獲取你要的數(shù)據(jù) 的,

然后就是通過我們剛剛講得修改document.domain的方法,讓我們能通過js完全控制這個iframe,這樣我們就可以讓iframe去發(fā) 送ajax請求,然后收到的數(shù)據(jù)我們也可以獲得了。
 

2、代理:

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

3、PHP端修改header(XHR2方式)

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

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

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

4、 location.hash + iframe

原理是利用location.hash來進(jìn)行傳值。

假設(shè)域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html傳遞信息。
1) cs1.html首先創(chuàng)建自動創(chuàng)建一個隱藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html頁面
2) cs2.html響應(yīng)請求后再將通過修改cs1.html的hash值來傳遞數(shù)據(jù)
3) 同時在cs1.html上加一個定時器,隔一段時間來判斷l(xiāng)ocation.hash的值有沒有變化,一旦有變化則獲取獲取hash值
注:由于兩個頁面不在同一個域下IE、Chrome不允許修改parent.location.hash的值,所以要借助于a.com域名下的一個代理iframe

代碼如下:
先是a.com下的文件cs1.html文件:

 

function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
    document.body.appendChild(ifr);
}

function checkHash() {
    try {
        var data = location.hash ? location.hash.substring(1) : '';
        if (console.log) {
            console.log('Now the data is '+data);
        }
    } catch(e) {};
}
setInterval(checkHash, 2000);


cnblogs.com域名下的cs2.html:
 

//模擬一個簡單的參數(shù)處理操作
switch(location.hash){
    case '#paramdo':
        callBack();
        break;
    case '#paramset':
        //do something……
        break;
}

function callBack(){
    try {
        parent.location.hash = 'somedata';
    } catch (e) {
        // ie、chrome的安全機制無法修改parent.location.hash,
        // 所以要利用一個中間的cnblogs域下的代理iframe
        var ifrproxy = document.createElement('iframe');
        ifrproxy.style.display = 'none';
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意該文件在"a.com"域下
        document.body.appendChild(ifrproxy);
    }
}


a.com下的域名cs3.html
 

//因為parent.parent和自身屬于同一個域,所以可以改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);



5、 window.name + iframe

window.name 的美妙之處:name 值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。

1) 創(chuàng)建a.com/cs1.html

2) 創(chuàng)建a.com/proxy.html,并加入如下代碼

 

<head>
  <script>
  function proxy(url, func){
    var isFirst = true,
        ifr = document.createElement('iframe'),
        loadFunc = function(){
          if(isFirst){
            ifr.contentWindow.location = 'http://a.com/cs1.html';
            isFirst = false;
          }else{
            func(ifr.contentWindow.name);
            ifr.contentWindow.close();
            document.body.removeChild(ifr);
            ifr.src = '';
            ifr = null;
          }
        };

    ifr.src = url;
    ifr.style.display = 'none';
    if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
    else ifr.onload = loadFunc;

    document.body.appendChild(iframe);
  }
</script>
</head>
<body>
  <script>
    proxy('http://www.baidu.com/', function(data){
      console.log(data);
    });
  </script>
</body>


3 在b.com/cs1.html中包含:
 

<script>
    window.name = '要傳送的內(nèi)容';
</script>



6、 postMessage(HTML5中的XMLHttpRequest Level 2中的API)

1) a.com/index.html中的代碼:

 

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若寫成'http://b.com/c/proxy.html'效果一樣
                                        // 若寫成'http://c.com'就不會執(zhí)行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>


2) b.com/index.html中的代碼:
 

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通過origin屬性判斷消息來源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 彈出"I was there!"
            alert(event.source);  // 對a.com、index.html中window對象的引用
                                  // 但由于同源策略,這里event.source不可以訪問window對象
        }
    }, false);
</script>


7、 CORS

CORS背后的思想,就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定請求或響應(yīng)是應(yīng)該成功,還是應(yīng)該失敗。

IE中對CORS的實現(xiàn)是xdr

 

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


其它瀏覽器中的實現(xiàn)就在xhr中
 

var xhr =  new XMLHttpRequest();
xhr.onreadystatechange = function () {
    if(xhr.readyState == 4){
        if(xhr.status >= 200 && xhr.status < 304 || xhr.status == 304){
            console.log(xhr.responseText);
        }
    }
}
xhr.open('get', 'http://www.baidu.com');
......
xhr.send(null);


實現(xiàn)跨瀏覽器的CORS
 

function createCORS(method, url){
    var xhr = new XMLHttpRequest();
    if('withCredentials' in xhr){
        xhr.open(method, url, true);
    }else if(typeof XDomainRequest != 'undefined'){
        var xhr = new XDomainRequest();
        xhr.open(method, url);
    }else{
        xhr = null;
    }
    return xhr;
}
var request = createCORS('get', 'http://www.baidu.com');
if(request){
    request.onload = function(){
        ......
    };
    request.send();
}

8、 web sockets

web sockets是一種瀏覽器的API,它的目標(biāo)是在一個單獨的持久連接上提供全雙工、雙向通信。(同源策略對web sockets不適用)

web sockets原理:在JS創(chuàng)建了web socket之后,會有一個HTTP請求發(fā)送到瀏覽器以發(fā)起連接。取得服務(wù)器響應(yīng)后,建立的連接會使用HTTP升級從HTTP協(xié)議交換為web sockt協(xié)議。

只有在支持web socket協(xié)議的服務(wù)器上才能正常工作。

 

var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
    var data = event.data;
}


 

如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答!! 點擊進(jìn)入論壇

發(fā)表評論 (898人查看0條評論)
請自覺遵守互聯(lián)網(wǎng)相關(guān)的政策法規(guī),嚴(yán)禁發(fā)布色情、暴力、反動的言論。
昵稱:
最新評論
2017年11月26日 15:09游客

websocket 好像不是跨域解決方案把,它本身也會有跨域問題把,它本身只是實現(xiàn)了服務(wù)器推送把!~!~

------分隔線----------------------------

其它欄目

· 建站教程
· 365學(xué)習(xí)

業(yè)務(wù)咨詢

· 技術(shù)支持
· 服務(wù)時間:9:00-18:00
365建站網(wǎng)二維碼

Powered by 365建站網(wǎng) RSS地圖 HTML地圖

copyright © 2013-2024 版權(quán)所有 鄂ICP備17013400號