欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript兩種跨域技術(shù)全面介紹

 更新時(shí)間:2014年04月16日 10:14:35   作者:  
JavaScript是一種在Web開發(fā)中經(jīng)常使用的前端動(dòng)態(tài)腳本技術(shù)。在JavaScript中,有一個(gè)很重要的安全性限制,被稱為“Same-Origin Policy”(同源策略)

這一策略對于JavaScript代碼能夠訪問的頁面內(nèi)容做了很重要的限制,即JavaScript只能訪問與包含它的文檔在同一域下的內(nèi)容。

JavaScript這個(gè)安全策略在進(jìn)行多iframe或多窗口編程、以及Ajax編程時(shí)顯得尤為重要。根據(jù)這個(gè)策略,在baidu.com下的頁面中包含的JavaScript代碼,不能訪問在google.com域名下的頁面內(nèi)容;甚至不同的子域名之間的頁面也不能通過JavaScript代碼互相訪問。對于Ajax的影響在于,通過XMLHttpRequest實(shí)現(xiàn)的Ajax請求,不能向不同的域提交請求,例如,在abc.example.com下的頁面,不能向def.example.com提交Ajax請求,等等。

然而,當(dāng)進(jìn)行一些比較深入的前端編程的時(shí)候,不可避免地需要進(jìn)行跨域操作,這時(shí)候“同源策略”就顯得過于苛刻。本文就這個(gè)問題,概括了跨域所需要的一些技術(shù)。

下面我們分兩種情況討論跨域技術(shù):首先討論不同子域的跨域技術(shù),然后討論完全不同域的跨域技術(shù)。

(一)不同子域的跨域技術(shù)。

我們分兩個(gè)問題來分別討論:第一個(gè)問題是如何跨不同子域進(jìn)行JavaScript調(diào)用;第二個(gè)問題是如何向不同子域提交Ajax請求。

先來解決第一個(gè)問題,假設(shè)example.com域下有兩個(gè)不同子域:abc.example.com和def.example.com?,F(xiàn)在假設(shè)在def.example.com下面有一個(gè)頁面,里面定義了一個(gè)JavaScript函數(shù):

復(fù)制代碼 代碼如下:
function funcInDef() {
    .....
}

我們想在abc.example.com下的某個(gè)頁面里調(diào)用上面的函數(shù)。再假設(shè)我們要討論的abc.example.com下面的這個(gè)頁面是以iframe形式嵌入在def.example.com下面那個(gè)頁面里的,這樣我們可能試圖在iframe里做如下調(diào)用:

復(fù)制代碼 代碼如下:
window.top.funcInDef();

好,我們注意到,這個(gè)調(diào)用是被前面講到的“同源策略”所禁止的,JavaScript引擎會(huì)直接拋出一個(gè)異常。
為了實(shí)現(xiàn)上述調(diào)用,我們可以通過修改兩個(gè)頁面的domain屬性的方法做到。例如,我們可以將上面在abc.example.com和def.example.com下的兩個(gè)頁面的頂端都加上如下的JavaScript代碼片段:
復(fù)制代碼 代碼如下:
document.domain = "example.com";

這樣,兩個(gè)頁面就變?yōu)橥蛄?,前面的調(diào)用也可以正常執(zhí)行了。

這里需要注意的一點(diǎn)是,一個(gè)頁面的document.domain屬性只能設(shè)置成一個(gè)更頂級的域名(除了一級域名),但不能設(shè)置成比當(dāng)前域名更深層的子域名。例如,abc.example.com的頁面只能將它的domain設(shè)置成example.com,不能設(shè)置成sub.abc.example.com,當(dāng)然也不能設(shè)置成一級域名com。

上面的例子討論的是兩個(gè)頁面屬于iframe嵌套關(guān)系的情況,當(dāng)兩個(gè)頁面是打開與被打開的關(guān)系時(shí),原理也完全一樣。

下面我們來解決第二個(gè)問題:如何向不同子域提交Ajax請求。
通常情況下,我們會(huì)用與下面類似的代碼來創(chuàng)建一個(gè)XMLHttpRequest對象:

復(fù)制代碼 代碼如下:
factories = [function() {
    return new XMLHttpRequest();
},
function() {
    return new ActiveXObject("Msxml2.XMLHTTP");
},
function() {
    return new ActiveXObject("Microsoft.XMLHTTP");
}];
function newRequest() {
    for (var i = 0; i & lt; factories.length; i++) {
        try {
            var factory = factories[i];
            return factory();
        } catch(e) {}
    }
    return null;
}

上面的代碼中引用ActiveXObject,是為了兼容IE6系列瀏覽器。每次我們調(diào)用newRequest函數(shù),就獲得了一個(gè)剛剛創(chuàng)建的Ajax對象,然后用這個(gè)Ajax對象來發(fā)送HTTP請求。例如,下面的代碼向abc.example.com發(fā)送了一個(gè)GET請求:
復(fù)制代碼 代碼如下:

var request = newRequest();
request.open("GET", "http://abc.example.com" );
request.send(null);

假設(shè)上面的代碼包含在一個(gè)abc.example.com域名下的頁面里,則這個(gè)GET請求可以正常發(fā)送成功,沒有任何問題。然而,如果現(xiàn)在要向def.example.com發(fā)送請求,則出現(xiàn)跨域問題,JavaScript引擎拋出異常。
解決的辦法是,在def.example.com域下放置一個(gè)跨域文件,假設(shè)叫crossdomain.html;然后將前面的newRequest函數(shù)的定義移到這個(gè)跨域文件中;最后像之前修改document.domain值的做法一樣,在crossdomain.html文件和abc.example.com域下調(diào)用Ajax的頁面頂端,都加上:

復(fù)制代碼 代碼如下:
document.domain = "example.com";


為了使用跨域文件,我們在abc.example.com域下調(diào)用Ajax的頁面中嵌入一個(gè)隱藏的指向跨域文件的iframe,例如:
復(fù)制代碼 代碼如下:
<iframe name="xd_iframe" style="display:none" src="http://def.example.com/crossdomain.html">
</iframe>


這時(shí)abc.example.com域下的頁面和跨域文件crossdomain.html都在同一個(gè)域(example.com)下,我們可以在abc.example.com域下的頁面中去調(diào)用crossdomain.html中的newRequest函數(shù):
復(fù)制代碼 代碼如下:
var request = window.frames["xd_iframe"].newRequest();

這樣獲得的request對象,就可以向http://def.example.com發(fā)送HTTP請求了。

(二)完全不同域的跨域技術(shù)。

如果頂級域名都不相同,例如example1.com和example2.com之間想通過JavaScript在前端通信,則所需要的技術(shù)更復(fù)雜些。

在講解不同域的跨域技術(shù)之前,我們首先明確一點(diǎn),下面要講的技術(shù)也同樣適用于前面跨不同子域的情況,因?yàn)榭绮煌佑蛑皇强缬騿栴}的一個(gè)特例。當(dāng)然,在恰當(dāng)?shù)那闆r下使用恰當(dāng)?shù)募夹g(shù),能夠保證更優(yōu)的效率和更高的穩(wěn)定性。

簡言之,根據(jù)不同的跨域需求,跨域技術(shù)可以歸為下面幾類:
1、JSONP跨域GET請求
2、通過iframe實(shí)現(xiàn)跨域
3、flash跨域HTTP請求
4、window.postMessage
下面詳細(xì)介紹各種技術(shù)。
1. JSONP。
利用在頁面中創(chuàng)建<script>節(jié)點(diǎn)的方法向不同域提交HTTP請求的方法稱為JSONP,這項(xiàng)技術(shù)可以解決跨域提交Ajax請求的問題。JSONP的工作原理如下所述:
假設(shè)在http://example1.com/index.php這個(gè)頁面中向http://example2.com/getinfo.php提交GET請求,我們可以將下面的JavaScript代碼放在http://example1.com/index.php這個(gè)頁面中來實(shí)現(xiàn):

復(fù)制代碼 代碼如下:
var eleScript= document.createElement("script");
eleScript.type = "text/javascript";
eleScript.src = "http://example2.com/getinfo.php";
document.getElementsByTagName("HEAD")[0].appendChild(eleScript);

當(dāng)GET請求從http://example2.com/getinfo.php返回時(shí),可以返回一段JavaScript代碼,這段代碼會(huì)自動(dòng)執(zhí)行,可以用來負(fù)責(zé)調(diào)用http://example1.com/index.php頁面中的一個(gè)callback函數(shù)。

JSONP的優(yōu)點(diǎn)是:它不像XMLHttpRequest對象實(shí)現(xiàn)的Ajax請求那樣受到同源策略的限制;它的兼容性更好,在更加古老的瀏覽器中都可以運(yùn)行,不需要XMLHttpRequest或ActiveX的支持;并且在請求完畢后可以通過調(diào)用callback的方式回傳結(jié)果。

JSONP的缺點(diǎn)則是:它只支持GET請求而不支持POST等其它類型的HTTP請求;它只支持跨域HTTP請求這種情況,不能解決不同域的兩個(gè)頁面之間如何進(jìn)行JavaScript調(diào)用的問題。

2. 通過iframe實(shí)現(xiàn)跨域。

iframe跨域的方式,功能強(qiáng)于JSONP,它不僅能用來跨域完成HTTP請求,還能在前端跨域?qū)崿F(xiàn)JavaScript調(diào)用。因此,完全不同域的跨域問題,通常采用iframe的方式來解決。

與JSONP技術(shù)通過創(chuàng)建<script>節(jié)點(diǎn)向不同的域提交GET請求的工作方式類似,我們也可以通過在http://example1.com/index.php頁面中創(chuàng)建指向http://example2.com/getinfo.php的iframe節(jié)點(diǎn)跨域提交GET請求。然而,請求返回的結(jié)果無法回調(diào)http://example1.com/index.php頁面中的callback函數(shù),因?yàn)槭艿健巴床呗浴钡挠绊憽?br>
為了解決這個(gè)問題,我們需要在example1.com下放置一個(gè)跨域文件,比如路徑是http://example1.com/crossdomain.html。

當(dāng)http://example2.com/getinfo.php這個(gè)請求返回結(jié)果的時(shí)候,它大體上有兩個(gè)選擇。
第一個(gè)選擇是,它可以在iframe中做一個(gè)302跳轉(zhuǎn),跳轉(zhuǎn)到跨域文件http://example1.com/crossdomain.html,同時(shí)將返回結(jié)果經(jīng)過URL編碼之后作為參數(shù)綴在跨域文件URL后面,例如http://example1.com/crossdomain.html?result=<URL-Encoding-Content>。

另一個(gè)選擇是,它可以在返回的頁面中再嵌入一個(gè)iframe,指向跨域文件,同時(shí)也是將返回結(jié)果經(jīng)過URL編碼之后作為參數(shù)綴在跨域文件URL后面。

在跨域文件中,包含一段JavaScript代碼,這段代碼完成的功能,是從URL中提取結(jié)果參數(shù),經(jīng)過一定處理后調(diào)用原來的http://example1.com/index.php頁面中的一個(gè)預(yù)先約定好的callback函數(shù),同時(shí)將結(jié)果參數(shù)傳給這個(gè)函數(shù)。http://example1.com/index.php頁面和跨域文件是在同一個(gè)域下的,因此這個(gè)函數(shù)調(diào)用可以通過??缬蛭募趇frame和原來的http://example1.com/index.php頁面的關(guān)系,在前述第一種選擇下,后者是前者的父窗口,在第二種選擇下,后者是前者的父窗口的父窗口。

根據(jù)前面的敘述,有了跨域文件之后,我們就可以實(shí)現(xiàn)通過iframe方式在不同域之間進(jìn)行JavaScript調(diào)用。這個(gè)調(diào)用過程可以完全跟HTTP請求無關(guān),例如有些站點(diǎn)可以支持動(dòng)態(tài)地調(diào)整在頁面中嵌入的第三方iframe的高度,這其實(shí)是通過在第三方iframe里面檢測自己頁面的高度變化,然后通過跨域方式的函數(shù)調(diào)用將這個(gè)變化告知父窗口來完成的。

既然利用iframe可以實(shí)現(xiàn)跨域JavaScript調(diào)用,那么跨域提交POST請求等其它類型的HTTP請求就不是難事。例如我們可以跨域調(diào)用目標(biāo)域的JavaScript代碼在目標(biāo)域下提交Ajax請求(GET/POST/etc.),然后將返回的結(jié)果再跨域傳原來的域。

使用iframe跨域,優(yōu)點(diǎn)是功能強(qiáng)大,支持各種瀏覽器,幾乎可以完成任何跨域想做的事情;缺點(diǎn)是實(shí)現(xiàn)復(fù)雜,要處理很多瀏覽器兼容問題,并且傳輸?shù)臄?shù)據(jù)不宜過大,過大了可能會(huì)超過瀏覽器對URL長度的限制,要考慮對數(shù)據(jù)進(jìn)行分段傳輸?shù)取?/P>

3. 利用flash實(shí)現(xiàn)跨域HTTP請求

據(jù)稱,flash在瀏覽器中的普及率高達(dá)90%以上。

flash代碼和JavaScript代碼之間可以互相調(diào)用,并且flash的“安全沙箱”機(jī)制與JavaScript的安全機(jī)制并不盡相同,因此,我們可以利用flash來實(shí)現(xiàn)跨域提交HTTP請求(支持GET/POST等)。
例如,我們用瀏覽器訪問http://example1.com/index.php這個(gè)頁面,在這個(gè)頁面中引用了http://example2.com/flash.swf這個(gè)flash文件,然后在flash代碼中向http://example3.com/webservice.php發(fā)送HTTP請求。

這個(gè)請求能否被成功發(fā)送,取決于在example3.com的根路徑下是否放置了一個(gè)crossdomain.xml以及這個(gè)crossdomain.xml的配置如何。flash的“安全沙箱”會(huì)保證:僅當(dāng)example3.com服務(wù)器在根路徑下確實(shí)放置了crossdomain.xml文件并且在這個(gè)文件中配置了允許接受來自example2.com的flash的請求時(shí),這個(gè)請求才能真正成功。下面是一個(gè)crossdomain.xml文件內(nèi)容的例子:

復(fù)制代碼 代碼如下:

<?xml version="1.0"?>
<cross-domain-policy>
    <allow-access-from domain="example2.com" />
</cross-domain-policy>

4. window.postMessage
  window.postMessage是HTML標(biāo)準(zhǔn)的下一個(gè)版本HTML5支持的一個(gè)新特性。受當(dāng)前互聯(lián)網(wǎng)技術(shù)突飛猛進(jìn)的影響,瀏覽器跨域通信的需求越來越強(qiáng)烈,HTML標(biāo)準(zhǔn)終于把跨域通信考慮進(jìn)去了。但目前HTML5仍然只是一個(gè)draft。
  window.postMessage是一個(gè)安全的實(shí)現(xiàn)直接跨域通信的方法。但是目前并不是所有瀏覽器都能支持,只有Firefox 3、Safari 4和IE8可以支持這個(gè)調(diào)用。

使用它向其它窗口發(fā)送消息的調(diào)用方式大概如下:

復(fù)制代碼 代碼如下:
otherWindow.postMessage(message, targetOrigin);

在接收的窗口,需要設(shè)置一個(gè)事件處理函數(shù)來接收發(fā)過來的消息:
復(fù)制代碼 代碼如下:
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
    if (event.origin !== "http://example.org:8080") return;
}

消息包含三個(gè)屬性:data、origin(攜帶發(fā)送窗口所在域的真實(shí)信息)和source(代表發(fā)送窗口的handle)。

安全性考慮:使用window.postMessage,必需要使用消息的origin和source屬性來驗(yàn)證發(fā)送者的身份,否則會(huì)造成XSS漏洞。

window.postMessage在功能上同iframe實(shí)現(xiàn)的跨域功能同樣強(qiáng)大,并且使用簡單,效率更高,但缺點(diǎn)是它目前在瀏覽器兼容方面有待提高。

需要對原文補(bǔ)充的是,在IE6,IE7下可利用IE的Opener可賦值為Object或Function的漏洞,提供postMessage方案的補(bǔ)充方案:
主頁面:

復(fù)制代碼 代碼如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>CrossDomain</title>
</head>
<body>
    <iframe src="http://sh-tanzhenlin/CrossDomain-child.html"
        frameborder="0" visible="false" height="0" width="0" id="ifrChild"></iframe>

    <script type="text/javascript">
        var child = document.getElementById("ifrChild");
        var openerObject = {
                funcInParent:function(arg){
                    alert(arg);
                    alert('executed by a function in parent page');
                }
            }

        if(!+'\v1' && !'1'[0]){ //test browser is ie6 or ie7  
            //crack
            child.contentWindow.opener = openerObject;
        }
        else{
            //postMessage showtime
        }

        function onClick(){
            //debugger;
            openerObject.funcInIframe('data from parent page ');
        }
    </script>
    <input type="button" value="click me" onclick="onClick()" />
</body>
</html>

用iframe內(nèi)嵌其它域下的頁面:

復(fù)制代碼 代碼如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
               <script type="text/javascript">
                        onload = function(){
                                if(!+'\v1' && !'1'[0]){ // test browser if is ie6 or ie7
                                        window.opener.funcInIframe=function(arg){
                                                alert(arg);
                                                alert('executed by a function in iframe');
                                        }
                                        window.opener.funcInParent('data from iframe')
                                }
                        }
                </script>
        </head>
        <body>
        </body>
</html>

注:postMessage方式正以意想不到的速度得到各種新瀏覽器的支持,應(yīng)予以著重考慮。

相關(guān)文章

  • 解決layer.prompt無效的問題

    解決layer.prompt無效的問題

    今天小編就為大家分享一篇解決layer.prompt無效的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • 讓IE8瀏覽器支持function.bind()方法

    讓IE8瀏覽器支持function.bind()方法

    function.bind()方法默認(rèn)IE8是不支持的,下面有個(gè)小技巧可完美解決這個(gè)問題,為此疑惑的朋友可以看看
    2014-10-10
  • JavaScript實(shí)現(xiàn)的經(jīng)典文件樹菜單效果

    JavaScript實(shí)現(xiàn)的經(jīng)典文件樹菜單效果

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)的經(jīng)典文件樹菜單效果,通過JavaScript結(jié)合json數(shù)組實(shí)現(xiàn)文件樹菜單的效果,非常簡單實(shí)用,需要的朋友可以參考下
    2015-09-09
  • Bootstrap框架安裝使用詳解

    Bootstrap框架安裝使用詳解

    這篇文章主要為大家詳細(xì)介紹了Bootstrap框架的安裝使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • js 觸發(fā)select onchange事件代碼

    js 觸發(fā)select onchange事件代碼

    select 或text的onchange事件需要手動(dòng)(通過鍵盤輸入)改變select或text的值才能觸發(fā),本文為大家介紹下使用js觸發(fā)select onchange事件
    2014-03-03
  • js字符串替換所有的指定字符或文字(推薦replaceAll方法)

    js字符串替換所有的指定字符或文字(推薦replaceAll方法)

    要實(shí)現(xiàn)js字符串替換所有的某個(gè)字符,推薦大家使用replaceAll方法,默認(rèn)不是所有瀏覽器都兼容,所以這里給出一個(gè)解決方案,需要的朋友可以參考下
    2014-07-07
  • JavaScript將字符串轉(zhuǎn)換成字符編碼列表的方法

    JavaScript將字符串轉(zhuǎn)換成字符編碼列表的方法

    這篇文章主要介紹了JavaScript將字符串轉(zhuǎn)換成字符編碼列表的方法,實(shí)例分析了javascript中charCodeAt函數(shù)的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • JavaScript數(shù)組去重的幾種方法

    JavaScript數(shù)組去重的幾種方法

    這篇文章主要給大家介紹了關(guān)于JavaScript數(shù)組去重的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • JavaScript中常見的七種繼承及實(shí)現(xiàn)

    JavaScript中常見的七種繼承及實(shí)現(xiàn)

    JS的繼承方式在我們面試的時(shí)候經(jīng)常會(huì)被問到,所以深入理解js繼承方式以及它們的優(yōu)缺點(diǎn)是非常有必要的。本文為大家整理了JavaScript中常見的七種繼承及實(shí)現(xiàn),需要的可以參考一下
    2023-03-03
  • JavaScript中省略元素對數(shù)組長度的影響

    JavaScript中省略元素對數(shù)組長度的影響

    這篇文章主要介紹了JavaScript中省略元素對數(shù)組長度的影響,本文給大家介紹的非常詳細(xì)具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-10-10

最新評論