跨域

JSONP

利用 <script>標(biāo)簽沒有跨域限制的“漏洞”來達(dá)到與第三方通訊的目的。
當(dāng)需要通訊時姻报,本站腳本創(chuàng)建一個元素瞒滴,地址指向第三方的API網(wǎng)址鹤耍,
如:<script src="http://www.example.net/api?param1=1&param2=2"></script>
并提供一個回調(diào)函數(shù)來接收數(shù)據(jù)(函數(shù)名可約定城豁,或通過地址參數(shù)傳遞)苟穆。 第三方產(chǎn)生的響應(yīng)為json數(shù)據(jù)的包裝(故稱之為jsonp,即json padding)
如:callback({"name":"hax","gender":"Male"}) 這樣瀏覽器會調(diào)用callback函數(shù)唱星,并傳遞解析后json對象作為參數(shù)雳旅。
優(yōu)點:簡單,老式瀏覽器全部支持间聊,服務(wù)器改造小攒盈。不需要XMLHttpRequest或ActiveX的支持。
缺點:只支持GET請求哎榴。

<!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>

后端

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即Cross Origin Resource Sharing(跨來源資源共享),通俗說就是我們所熟知的跨域請求尚蝌。眾所周知偷遗,在以前,跨域可以采用代理驼壶、JSONP等方式,而在Modern瀏覽器面前喉酌,這些終將成為過去式热凹,因為有了CORS。

CORS在最初接觸的時候只大概了解到泪电,通過服務(wù)器端設(shè)置Access-Control-Allow-Origin響應(yīng)頭般妙,即可使指定來源像訪問同源接口一樣訪問跨域接口,最近在使用CORS的時候相速,由于需要傳輸自定義Header信息碟渺,發(fā)現(xiàn)原來CORS的規(guī)范定義遠(yuǎn)不止這些。

CORS可以分成簡單請求和復(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)中填寫并以逗號進(jìn)行分隔
如果僅僅是簡單請求蚜厉,那么即便不用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)對這兩項進(jìn)行回復(fù),以讓瀏覽器 ## 標(biāo)題頭
確定請求是否能夠成功完成娜膘。

復(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ā)送冯键。

通caniuse.com得知惹盼,目前大部分Modern瀏覽器已經(jīng)支持完整的CORS,但I(xiàn)E直到IE11才完美支持惫确,所以對于PC網(wǎng)站手报,還是建議采用其他解決方案蚯舱,如果僅僅是移動端網(wǎng)站,大可放心使用掩蛤。
代碼

<!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>

后端

</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);

})

降域 修改document.domain

A頁面

<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>

B頁面

<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>

window.postMessage方法

頁面A

<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>

頁面B

<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閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晰奖,死亡現(xiàn)場離奇詭異,居然都是意外死亡腥泥,警方通過查閱死者的電腦和手機(jī)匾南,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來道川,“玉大人午衰,你說我怎么就攤上這事∶疤眩” “怎么了臊岸?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尊流。 經(jīng)常有香客問我帅戒,道長,這世上最難降的妖魔是什么崖技? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任逻住,我火速辦了婚禮,結(jié)果婚禮上迎献,老公的妹妹穿的比我還像新娘瞎访。我一直安慰自己,他們只是感情好吁恍,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布扒秸。 她就那樣靜靜地躺著,像睡著了一般冀瓦。 火紅的嫁衣襯著肌膚如雪伴奥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天翼闽,我揣著相機(jī)與錄音拾徙,去河邊找鬼。 笑死感局,一個胖子當(dāng)著我的面吹牛尼啡,可吹牛的內(nèi)容都是我干的暂衡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼玄叠,長吁一口氣:“原來是場噩夢啊……” “哼古徒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起读恃,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤隧膘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寺惫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疹吃,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年西雀,在試婚紗的時候發(fā)現(xiàn)自己被綠了萨驶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡艇肴,死狀恐怖腔呜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情再悼,我是刑警寧澤核畴,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站冲九,受9級特大地震影響谤草,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莺奸,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一丑孩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灭贷,春花似錦温学、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至古拴,卻和暖如春箩帚,著一層夾襖步出監(jiān)牢的瞬間真友,已是汗流浹背黄痪。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留盔然,地道東北人桅打。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓是嗜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挺尾。 傳聞我的和親對象是個殘疾皇子鹅搪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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