JavaScript跨域

JSONP

jsonp其實是由兩部分組成的:回調(diào)函數(shù)和數(shù)據(jù)∧鳎回調(diào)函數(shù)是當(dāng)響應(yīng)到來時應(yīng)該在頁面中調(diào)用的函數(shù),而數(shù)據(jù)就是傳入回調(diào)函數(shù)中的json參數(shù)。利用的是script標(biāo)簽中src可以引用不同域上js文件的思想楚里,進行跨域。

  • jsonp的優(yōu)點: 它不像XHR對象實現(xiàn)ajax請求那樣受到同源政策的限制猎贴,它的兼容性更好班缎,XHR在進行ajax請求時,為了兼容IE她渴,還需創(chuàng)建ActiveX對象达址。并且在請求完畢之后可以通過回調(diào)函數(shù)的方式將結(jié)果回傳
  • jsonp的缺點: 它只支持get請求而不支持post等其它類型的HTTP請求;它只支持跨域HTTP請求這種情況趁耗,不能解決不同域的兩個頁面之間如何進行javascript調(diào)用問題
    實驗代碼:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>news</title>
    <style>
        .container{
            width: 900px;
            margin: 0 auto;
        }
    </style>
</head>
<body>
<div class="container">
    <ul class="news">
        <li>第11日前瞻:中國沖擊4金 博爾特再戰(zhàn)</li>
        <li>男雙力爭會師決賽 </li>
        <li>女排將死磕巴西沉唠!</li>
    </ul>
    <button class="change">換一組</button>
</div>

<!--<script src="http://localhost:8080/a.js"></script>-->
<script>
    $('.change').addEventListener('click', function () {
        var script=document.createElement('script');
        script.src='http://localhost:8080/getNews?callback=appendHtml';
        document.head.appendChild(script);
        document.head.removeChild(script);
    });
  function appendHtml(news) {
        var html ='';
        for(var i=0;i<news.length;i++){
            html+='<li>'+news[i]+'</li>';
        }
        console.log(html);
        $('.news').innerHTML=html;
    }

    function $(id){
        return document.querySelector(id);
    }
</script>
</body>
</html>

服務(wù)器代碼:

app.get('/getNews', function (req, res) {

    var news = [
        "1.三國",
        "2.水滸",
        "3.紅樓",
        "4.西游",
        "5.聊齋",
        "6.山海",
        "7.道德",
        "8.三字"
    ]
    var data = [];
    for (var i = 0; i < 3; i++) {
        var index = parseInt(Math.random() * news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }

    var cb = req.query.callback;
    if (cb) {
        res.send(cb + '(' + JSON.stringify(data) + ')');
    } else {
        res.send(data);
    }

})

CORS

cors簡單與復(fù)雜請求解析

CORS與JSONP對比:
CORS無疑更為先進,方便和可靠苛败。
1.jsonp只能實現(xiàn)get請求满葛,而CORS支持所有類型的HTTP請求
2.使用CORS,開發(fā)者可以使用普通的XHR發(fā)起請求和獲得數(shù)據(jù)罢屈,比起jsonp有更好的錯誤處理
3.jsonp主要被老的瀏覽器支持嘀韧,而絕大多數(shù)現(xiàn)代瀏覽器都已經(jīng)支持CORS

CORS可以分成兩種:

1、簡單請求
2缠捌、復(fù)雜請求

一個簡單的請求大致如下:
HTTP方法是下列之一

  • HEAD
  • GET
  • POST

HTTP頭包含

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type锄贷,但僅能是下列之一
    application/x-www-form-urlencoded
    multipart/form-data
    text/plain

任何一個不滿足上述要求的請求,即被認(rèn)為是復(fù)雜請求曼月。一個復(fù)雜請求不僅有包含通信內(nèi)容的請求谊却,同時也包含預(yù)請求(preflight request)。

簡單請求的發(fā)送從代碼上來看和普通的XHR沒太大區(qū)別哑芹,但是HTTP頭當(dāng)中要求總是包含一個域(Origin)的信息炎辨。該域包含協(xié)議名、地址以及一個可選的端口绩衷。不過這一項實際上由瀏覽器代為發(fā)送蹦魔,并不是開發(fā)者代碼可以觸及到的。

簡單請求的部分響應(yīng)頭及解釋如下:
  • Access-Control-Allow-Origin(必含)- 不可省略咳燕,否則請求按失敗處理勿决。該項控制數(shù)據(jù)的可見范圍,如果希望數(shù)據(jù)對任何人都可見招盲,可以填寫”*”低缩。
  • Access-Control-Allow-Credentials(可選) – 該項標(biāo)志著請求當(dāng)中是否包含cookies信息,只有一個可選值:true(必為小寫)。如果不包含cookies咆繁,請略去該項讳推,而不是填寫false。這一項與XmlHttpRequest2對象當(dāng)中的withCredentials屬性應(yīng)保持一致玩般,即withCredentials為true時該項也為true银觅;withCredentials為false時,省略該項不寫坏为。反之則導(dǎo)致請求失敗究驴。
  • Access-Control-Expose-Headers(可選) – 該項確定XmlHttpRequest2對象當(dāng)中g(shù)etResponseHeader()方法所能獲得的額外信息。
    通常情況下匀伏,getResponseHeader()方法只能獲得如下的信息:
    Cache-Control
    Content-Language
    Content-Type
    Expires
    Last-Modified
    Pragma
    當(dāng)你需要訪問額外的信息時洒忧,就需要在這一項當(dāng)中填寫并以逗號進行分隔

如果僅僅是簡單請求,那么即便不用CORS也沒有什么大不了够颠,但CORS的復(fù)雜請求就令CORS顯得更加有用了熙侍。簡單來說,任何不滿足上述簡單請求要求的請求履磨,都屬于復(fù)雜請求蛉抓。比如說你需要發(fā)送PUT、DELETE等HTTP動作蹬耘,或者發(fā)送Content-Type: application/json的內(nèi)容芝雪。

復(fù)雜請求表面上看起來和簡單請求使用上差不多减余,但實際上瀏覽器發(fā)送了不止一個請求综苔。其中最先發(fā)送的是一種”預(yù)請求”,此時作為服務(wù)端位岔,也需要返回”預(yù)回應(yīng)”作為響應(yīng)如筛。預(yù)請求實際上是對服務(wù)端的一種權(quán)限請求,只有當(dāng)預(yù)請求成功返回抒抬,實際請求才開始執(zhí)行杨刨。

預(yù)請求以O(shè)PTIONS形式發(fā)送,當(dāng)中同樣包含域擦剑,并且還包含了兩項CORS特有的內(nèi)容:
  • Access-Control-Request-Method – 該項內(nèi)容是實際請求的種類妖胀,可以是GET、POST之類的簡單請求惠勒,也可以是PUT赚抡、DELETE等等。
  • Access-Control-Request-Headers – 該項是一個以逗號分隔的列表纠屋,當(dāng)中是復(fù)雜請求所使用的頭部涂臣。

顯而易見,這個預(yù)請求實際上就是在為之后的實際請求發(fā)送一個權(quán)限請求售担,在預(yù)回應(yīng)返回的內(nèi)容當(dāng)中赁遗,服務(wù)端應(yīng)當(dāng)對這兩項進行回復(fù)署辉,以讓瀏覽器確定請求是否能夠成功完成。

復(fù)雜請求的部分響應(yīng)頭及解釋如下:
  • Access-Control-Allow-Origin(必含) – 和簡單請求一樣的岩四,必須包含一個域哭尝。
  • Access-Control-Allow-Methods(必含) – 這是對預(yù)請求當(dāng)中Access-Control-Request-Method的回復(fù),這一回復(fù)將是一個以逗號分隔的列表剖煌。盡管客戶端或許只請求某一方法刚夺,但服務(wù)端仍然可以返回所有允許的方法,以便客戶端將其緩存末捣。
  • Access-Control-Allow-Headers(當(dāng)預(yù)請求中包含Access-Control-Request-Headers時必須包含) – 這是對預(yù)請求當(dāng)中Access-Control-Request-Headers的回復(fù)侠姑,和上面一樣是以逗號分隔的列表,可以返回所有支持的頭部箩做。這里在實際使用中有遇到莽红,所有支持的頭部一時可能不能完全寫出來,而又不想在這一層做過多的判斷邦邦,沒關(guān)系安吁,事實上通過request的header可以直接取到Access-Control-Request-Headers,直接把對應(yīng)的value設(shè)置到Access-Control-Allow-Headers即可燃辖。
  • Access-Control-Allow-Credentials(可選) – 和簡單請求當(dāng)中作用相同鬼店。
  • Access-Control-Max-Age(可選) – 以秒為單位的緩存時間。預(yù)請求的的發(fā)送并非免費午餐黔龟,允許時應(yīng)當(dāng)盡可能緩存妇智。

一旦預(yù)回應(yīng)如期而至,所請求的權(quán)限也都已滿足氏身,則實際請求開始發(fā)送巍棱。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>news</title>
    <style>
        .container{
            width: 900px;
            margin: 0 auto;
        }
    </style>
</head>
<body>
<div class="container">
    <ul class="news">
        <li>第11日前瞻:中國沖擊4金 博爾特再戰(zhàn)</li>
        <li>男雙力爭會師決賽 </li>
        <li>女排將死磕巴西!</li>
    </ul>
    <button class="change">換一組</button>
</div>

<script>

    $('.change').addEventListener('click', function(){

        var xhr = new XMLHttpRequest();
        xhr.open('get', 'http://a.jirengu:8080/getNews', true);
        xhr.send();
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.status === 200){
                appendHtml( JSON.parse(xhr.responseText) )
            }
        }
    })

    function appendHtml(news){
        var html = '';
        for( var i=0; i<news.length; i++){
            html += '<li>' + news[i] + '</li>';
        }
        console.log(html);
        $('.news').innerHTML = html;

    }

    function $(id){
        return document.querySelector(id);
    }
</script>
</body>
//服務(wù)器
</html>app.get('/getNews', function (req, res) {

    var news = [
        "1.三國",
        "2.水滸",
        "3.紅樓",
        "4.西游",
        "5.聊齋",
        "6.山海",
        "7.道德",
        "8.三字"
    ]
    var data = [];
    for (var i = 0; i < 3; i++) {
        var index = parseInt(Math.random() * news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }
    //res.header("Access-Control-Allow-Origin", "http://c.jrg.com:8080"); 
    res.header("Access-Control-Allow-Origin", "*");
    res.send(data);

})

降域

頁面1:

<html>
<style>
    .ct{
        width: 910px;
        margin: auto;
    }
    .main{
        float: left;
        width: 450px;
        height: 300px;
        border: 1px solid #ccc;
    }
    .main input{
        margin: 20px;
        width: 200px;
    }
    .iframe{
        float: right;
    }

    iframe{
        width: 450px;
        height: 300px;
        border: 1px dashed #ccc;
    }
</style>

<div class="ct">
    <h1>跨域測試</h1>
    <div class="main">
        <input type="text" placeholder="http://a.jrg.com:8080/a.html">
    </div>

    <iframe src="http://b.jrg.com:8080/b.html" frameborder="0" ></iframe>

</div>


<script>
    //URL: http://a.jrg.com:8080/a.html

    document.querySelector('.main input').addEventListener('input', function(){
        console.log(this.value);
        window.frames[0].document.querySelector('input').value = this.value;
    })
    
    document.domain = "jrg.com";
</script>
</html>

頁面2:

<html>
<style>
    html,body{
        margin: 0;
    }
    input{
        margin: 20px;
        width: 200px;
    }
</style>

    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
<script>

// URL: http://b.jrg.com:8080/b.html
 
document.querySelector('#input').addEventListener('input', function(){
    window.parent.document.querySelector('input').value = this.value;
})

document.domain = 'jrg.com';

</script>
</html>

postMessage

頁面1:

<style>
    .ct{
        width: 910px;
        margin: auto;
    }
    .main{
        float: left;
        width: 450px;
        height: 300px;
        border: 1px solid #ccc;
    }
    .main input{
        margin: 20px;
        width: 200px;
    }
    .iframe{
        float: right;
    }

    iframe{
        width: 450px;
        height: 300px;
        border: 1px dashed #ccc;
    }
</style>

<div class="ct">
    <h1>跨域postMessage測試</h1>
    <div class="main">
        <input type="text" placeholder="http://a.jrg.com:8080/a.html">
    </div>

    <iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>

</div>


<script>
    //URL: http://a.jrg.com:8080/a.html

    $('.main input').addEventListener('input', function(){
        console.log(this.value);
        window.frames[0].postMessage(this.value,'*');
    })

    window.addEventListener('message',function(e) {
        $('.main input').value = e.data
        console.log(e.data);
    });

    function $(id){
        return document.querySelector(id);
    }

</script>

頁面2:

<html>
<style>
    html,body{
        margin: 0;
    }
    input{
        margin: 20px;
        width: 200px;
    }
</style>

    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
<script>

// URL: http://b.jrg.com:8080/b.html
 
$('#input').addEventListener('input', function(){
    window.parent.postMessage(this.value, '*');
})

window.addEventListener('message',function(e) {
        $('#input').value = e.data
    console.log(e.data);
});

function $(id){
    return document.querySelector(id);
}   

</script>
</html>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛋欣,一起剝皮案震驚了整個濱河市航徙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陷虎,老刑警劉巖到踏,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異尚猿,居然都是意外死亡窝稿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門谊路,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讹躯,“玉大人,你說我怎么就攤上這事〕碧荩” “怎么了骗灶?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秉馏。 經(jīng)常有香客問我耙旦,道長,這世上最難降的妖魔是什么萝究? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任免都,我火速辦了婚禮,結(jié)果婚禮上帆竹,老公的妹妹穿的比我還像新娘绕娘。我一直安慰自己,他們只是感情好栽连,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布险领。 她就那樣靜靜地躺著,像睡著了一般秒紧。 火紅的嫁衣襯著肌膚如雪绢陌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天熔恢,我揣著相機與錄音脐湾,去河邊找鬼。 笑死叙淌,一個胖子當(dāng)著我的面吹牛秤掌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凿菩,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼机杜,長吁一口氣:“原來是場噩夢啊……” “哼帜讲!你這毒婦竟也來了衅谷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤似将,失蹤者是張志新(化名)和其女友劉穎获黔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體在验,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡玷氏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了腋舌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盏触。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赞辩,到底是詐尸還是另有隱情雌芽,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布辨嗽,位于F島的核電站世落,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏糟需。R本人自食惡果不足惜屉佳,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洲押。 院中可真熱鬧武花,春花似錦、人聲如沸杈帐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娘荡。三九已至干旁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炮沐,已是汗流浹背争群。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留大年,地道東北人换薄。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像翔试,于是被迫代替她去往敵國和親轻要。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容