JS 跨域小結

輸出就是最好的輸入,嗯,有道理。

乾貨在後面,能夠跳過這部分

有一個理論,叫專家盲點,你問一個氣象家,什麼是風,他會一臉正經,一字一句的說:‘風是由空氣流動引發的一種天然現象,它是由太陽輻射熱引發的。。。’而後你就。。。若是回答的是:‘你感覺一下,這就是風’,你是否是會瞬間明白呢。若是你想檢驗你是否學懂了一個知識點,你能夠這樣檢驗,試着向一個小白解釋這個知識點,,看看他能不能聽懂。我就是想檢驗一下偶本身,,也許沒人看,但,根本目的不是爲了讓別人看到,由於知識有輸出,你就會有輸入。。html

跨域究竟是啥?

好比:你本身作了一個Web應用,功能是展現各地天氣狀況,好了,你的頁面都已經寫好了,但我改如何獲取各地的天氣狀況呢,這就須要你經過請求去獲取,好比你的天氣數據來源是中國天氣網,那麼你就須要向該網站的天氣API發送請求獲取天氣數據。可是,,人家的數據你是訪問不到的,由於瀏覽器不會容許你的網站從第三方網站獲取數據,這是由於瀏覽器的同源政策,所謂同源,指兩個網站的協議,域名,端口號都相同,這樣兩個網站直接才能相互通訊。同源政策是網景公司引入瀏覽器的,如今瀏覽器都支持,目的是爲了保證用戶信息安全。
可是,安全是安全了,但咱們的功能該如何實現呢?即如何向第三方發起請求,兩者進行通訊呢?這就是所謂的跨域前端

如何實現跨域呢?

如今咱們知道了,須要跨域才能進行兩個非同源的網站的通訊,那具體該如何實現呢?有如下幾種方法:chrome

  • JSONP
    額,,不要先糾結這個名詞。看看他是如何實現的吧。

JSONP原理: 利用script標籤沒有跨域限制的特性,讓它指向第三方網站,即用script標籤發出請求,但它請求的資源會被當成JS去執行,那如何讓這個返回的數據可以被我所用,可以被獲得執行呢?這就須要第三方網站給你的數據是一個數據JSON包,它返回的數據,不是簡單的數據,而是用一個回調函數包裝起來的,做爲函數參數返回給你本身已經定義好的函數,這個函數的功能就是你對數據的操做處理。這樣就能夠請求到底三方的資源了,,但前提是須要第三方給你提供這個請求接口你纔可以請求到數據。後端

實例;功能點擊按鈕,實現換組新聞:

前端代碼跨域

<!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金 博爾特再戰</li>
            <li>男雙力爭會師決賽 </li>
            <li>女排將死磕巴西!</li>
        </ul>
        <button class="change">換一組</button>
    </div>

    <script>
        $('.change').addEventListener('click', function() {
            var script = document.createElement('script'); //建立一個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>



</html>

後端數據mock瀏覽器

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

    var news = [
        "第11日前瞻:中國衝擊4金 博爾特再戰200米羽球",
        "正直播柴飈/洪煒出戰 男雙力爭會師決賽",
        "女排將死磕巴西!郎平安排男陪練模仿對方核心",
        "沒有中國選手和巨星的110米欄 咱們還看嗎?",
        "中英上演奧運金牌大戰",
        "博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多",
        "最「出櫃」奧運?同性之愛閃耀里約",
        "下跪拜謝與洪荒之力同樣 都是真情流露"
    ]
    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) + ')'); //若是有:就會返回appendHtml()
    } else {
        res.send(data);
    }


})
  • 第二種方法,CORS實現跨域。
    對於AJAX來講,要實現跨域請求,前端代碼不須要作任何改變,就像用AJAX發送同源請求同樣,,只不過須要在後端進行一些額外配置,就是在服務端的響應頭部增長一段代碼處理便可,整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。

前端代碼安全

<!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金 博爾特再戰</li>
            <li>男雙力爭會師決賽 </li>
            <li>女排將死磕巴西!</li>
        </ul>
        <button class="change">換一組</button>
    </div>

    <script>
        //注意,AJAX跨域並不須要前端代碼改變什麼,就和正常AJAX代碼同樣寫就能夠。。即,,AJAX自己就是支持跨域,只是後端須要支持
        $('.change').addEventListener('click', function() {
            var xhr = new XMLHttpRequest();
            xhr.open('get', 'http://b.jrg.com: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>



</html>

後端數據mock服務器

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

    var news = [
        "第11日前瞻:中國衝擊4金 博爾特再戰200米羽球",
        "正直播柴飈/洪煒出戰 男雙力爭會師決賽",
        "女排將死磕巴西!郎平安排男陪練模仿對方核心",
        "沒有中國選手和巨星的110米欄 咱們還看嗎?",
        "中英上演奧運金牌大戰",
        "博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多",
        "最「出櫃」奧運?同性之愛閃耀里約",
        "下跪拜謝與洪荒之力同樣 都是真情流露"
    ]
    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://a.jrg.com:8080"); //服務端在響應投加上容許跨域請求的網站便可,只有它容許的才能夠訪問到
    //res.header("Access-Control-Allow-Origin", "*");    *表示接收全部跨域請求
    res.send(data);
})
  • 第三種方法,降域。
    當你在一個網頁中用iframe標籤引入另外一個網站時,有兩種狀況,1,該網頁是你本身的一個網頁,頂級域名和父的域名是同樣的,只是二級域名不一樣,這種狀況下,能夠經過降域的方式實現兩個窗口之間的通訊。降域的關鍵:經過設置網頁的 domain 屬性實現。
    父窗口代碼
<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="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>

子窗口代碼app

<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實現
    上面直說了一種狀況,,而另一種狀況就是,這兩個網站徹底不一樣同源,如何實現兩者之間的通訊呢,HTML5爲了解決這個問題,引入了一個全新的API:跨文檔通訊 API(Cross-document messaging)。這個API爲window對象新增了一個window.postMessage方法,容許跨窗口通訊,不論這兩個窗口是否同源。
    關鍵就是調用 postMessage這個方法。
    父窗口
<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>使用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>

</html>

子窗口dom

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

說明:

先後端代碼都須要在靜態服務器上運行,我用的是Nojs下的srver-mock工具。

相關文章
相關標籤/搜索