JS 跨域小结

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

干货在后面,可以跳过这部分

有一个理论,叫专家盲点,你问一个气象家,什么是风,他会一脸正经,一字一句的说:‘风是由空气流动引起的一种自然现象,它是由太阳辐射热引起的。。。’然后你就。。。如果回答的是:‘你感受一下,这就是风’,你是不是会瞬间明白呢。如果你想检验你是否学懂了一个知识点,你可以这样检验,试着向一个小白解释这个知识点,,看看他能不能听懂。我就是想检验一下偶自己,,也许没人看,但,根本目的不是为了让别人看到,因为知识有输出,你就会有输入。。

跨域到底是啥?

比如:你自己做了一个Web应用,功能是展示各地天气情况,好了,你的页面都已经写好了,但我改如何获取各地的天气情况呢,这就需要你通过请求去获取,比如你的天气数据来源是中国天气网,那么你就需要向该网站的天气API发送请求获取天气数据。但是,,人家的数据你是访问不到的,因为浏览器不会允许你的网站从第三方网站获取数据,这是因为浏览器的同源政策,所谓同源,指两个网站的协议,域名,端口号都相同,这样两个网站直接才能相互通信。同源政策是网景公司引入浏览器的,现在浏览器都支持,目的是为了保证用户信息安全。
但是,安全是安全了,但我们的功能该如何实现呢?即如何向第三方发起请求,二者进行通信呢?这就是所谓的跨域

如何实现跨域呢?

现在我们知道了,需要跨域才能进行两个非同源的网站的通信,那具体该如何实现呢?有以下几种方法:

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

子窗口代码


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

子窗口

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

转载于:https://www.cnblogs.com/bold1/p/7290651.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值