跨域的幾種解決方案

方法一:JSONP

原理

JSONP(JSON with padding),padding有填補(bǔ)的意思,所以JSONP也就是往JSON上加一些東西。在HTML 中 script 標(biāo)簽可以加載其他域下的js,比如我們經(jīng)常引入一個其他域下線上cdn的jQuery。那么我們可以利用這個特性來向其他域請求數(shù)據(jù)。

對于HTML中的script標(biāo)簽,src中請求的數(shù)據(jù)返回后會被當(dāng)做Javascript代碼來運(yùn)行,所以當(dāng)后臺返回?cái)?shù)據(jù)的時候,不能直接返回?cái)?shù)組或者字符串之類的,應(yīng)該對數(shù)據(jù)進(jìn)行“包裹”,也就是JSONP中的P代表的padding,加點(diǎn)東西。下面請看例子。

舉例

第一步

我們現(xiàn)在向后臺的約定了一個獲取天氣的接口getWeather,然后在script標(biāo)簽中寫一個這樣的請求:
<script src="a.com/getWeather?callback=showData"></script>

第二步

后臺收到/getWeather這個路由后,應(yīng)該是直接向我返回一個JSON格式的數(shù)據(jù),其中包含天氣,比如這個數(shù)據(jù),{ "beijing" : "sunny" }。但對于script標(biāo)簽,返回的數(shù)據(jù)是要作為Javascript代碼執(zhí)行的,上面返回的數(shù)據(jù)應(yīng)該進(jìn)行“包裹”,例如變成這樣showData( { "beijing" : "sunny" } ),服務(wù)器端寫法如下:

var http = require('http');
var url = require('url');
var fs = require('fs');
var path = require('path');

var server = http.createServer(function(req,res){
    var pathObj = url.parse(req.url,true);
//處理getWeather請求
if(pathObj.pathname === '/getWeather'){
        var callback = pathObj.query.callback
        console.log(callback)
        res.write(`${callback}({"beijing":"sunny"})`)
        res.end()
    }else{
        res.end()
    }
})
server.listen(8080);

結(jié)果

response

控制臺打印出結(jié)果

方法二:CORS

原理

CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 ajax 跨域請求資源的方式,支持現(xiàn)代瀏覽器,IE支持10以上。 實(shí)現(xiàn)方式很簡單,當(dāng)你使用 XMLHttpRequest 發(fā)送請求時,瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會給該請求加一個請求頭:Origin,Origin對應(yīng)的值是當(dāng)前網(wǎng)站的域名。后臺進(jìn)行一系列處理,如果確定接受請求則在返回結(jié)果中加入一個響應(yīng)頭:Access-Control-Allow-Origin; 瀏覽器判斷該響應(yīng)頭中是否包含 Origin 的值(也就是Access-Control-Allow-Origin的值和Origin的值對應(yīng)),如果有則瀏覽器會處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù),如果不包含,瀏覽器直接駁回,這時我們無法拿到響應(yīng)數(shù)據(jù)。所以 CORS 的表象是讓你覺得它與同源的 ajax 請求沒啥區(qū)別,代碼完全一樣。

舉例

  • HTML代碼
//打開此頁面使用的地址是a.com:8080
<!DOCTYPE html>
<html>
<head>
    <title>a.html</title>
    <meta charset="utf-8">
</head>
<body>
    <button id="click">發(fā)送請求</button>
    <script type="text/javascript">
            click.onclick = function(){
            var xhr = new XMLHttpRequest()
            xhr.open('GET', 'http://b.com:8080/getWeather')
            xhr.onload = function(){
                console.log(xhr.responseText)
            }
            xhr.send()
        }   
    </script>
</body>
</html>
  • 服務(wù)端代碼
var http = require('http');
var url = require('url');
var fs = require('fs');
var path = require('path');

var server = http.createServer(function(req,res){
    var pathObj = url.parse(req.url,true);
//處理getWeather請求
if(pathObj.pathname === '/getWeather'){
        var weather = {"beijing":"sunny"}
        res.setHeader('Access-Control-Allow-Origin', 'http://a.com:8080')
        res.write(JSON.stringify(weather))
        res.end()
    }else{
        res.end()
    }
})
server.listen(8080);
Network查看效果

方法三:降域

原理

主要用于頁面上iframe跨域的操作。降域就是通過在兩個頁面使用 document.domain方法,將兩個頁面的域名統(tǒng)一,由此來實(shí)現(xiàn)跨域。不過這要求兩個頁面的域名有公共的部分。

舉例

  • a.html
<!DOCTYPE html>
<html>
<head>
    <title>a.html</title>
    <meta charset="utf-8">
    <style type="text/css">
        .windowB {
            height: 250px;
            width: 500px;
            margin: 10px 10px;
            border: 1px #ccc solid;
        }
    </style>
</head>
<body>
    <h1>this is a.html</h1>
    <iframe class="windowB" src="http://b.common.com:8080/b.html"></iframe>
</body>
</html>
  • b.html
<!DOCTYPE html>
<html>
<head>
    <title>b.html</title>
</head>
<body>
    <h1>this is b.html</h1>
    <script type="text/javascript">
        document.domain = 'common.com'
    </script>
</body>
</html>

效果

控制臺可獲取iframe中信息

方法四:postMessage

原理

當(dāng)前頁面要和iframe進(jìn)行數(shù)據(jù)交互的時候,可以選中需要交互的iframe,然后利用postMessage這個方法向它發(fā)送消息,然后在iframe頁面上監(jiān)聽message這個事件,對發(fā)來的信息做處理,這樣就可以實(shí)現(xiàn)數(shù)據(jù)的交互。

舉例

  • a.html
<!DOCTYPE html>
<html>
<head>
    <title>a.html</title>
    <meta charset="utf-8">
    <style type="text/css">
        .windowB {
            height: 250px;
            width: 500px;
            margin: 10px 10px;
            border: 1px #ccc solid;
        }
    </style>
</head>
<body>
    <h1>this is a.html</h1>
    <button id="click">發(fā)送請求</button>
    <input type="text" name="data" placeholder="請輸入文字">
    <script type="text/javascript">
            function $(e){
                var element = document.querySelector(e)
                return element
            }
//選中input,綁定事件,當(dāng)輸入信息時,在iframe中展示,*表示在任何域下都可以接受
            $('input').addEventListener('input', function(){
                window.frames[0].postMessage(this.value,'*')
            })
    </script>
</body>
</html>
  • b.html
<!DOCTYPE html>
<html>
<head>
    <title>b.html</title>
    <meta charset="utf-8">
</head>
<body>
    <h1>this is b.html</h1>
    <input type="text" name="data2" placeholder="顯示數(shù)據(jù)">
    <script type="text/javascript">
         function $(e){
                var element = document.querySelector(e)
                return element
            }
        window.addEventListener('message',function(e){
            $('input').value = e.data
        })
    </script>
</body>
</html>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容