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工具。

相关文章
相关标签/搜索