關於跨域

在使用Vue搭建的一個後端管理系統中,我使用axios請求本地的Node環境下的接口,可是請求失敗,而後我錯誤信息是:
331552554043_.pic.jpg
大概意思就是不能訪問http://localhost:8080
個人Vue項目端口是http://localhost:8081,Node服務端運行在http://localhost:8080端口上,也就是說由於請求端口和響應端口不一致,因此請求失敗。
我也在網上查看了一些關於跨域出現的緣由及解決的方法,並記錄下來。html

爲何會有跨域

跨域一句話的理解就是:服務端和請求端的地址不同。

什麼是跨域

Ajax 的便利性你們都清楚,能夠在不向服務器提交完整的頁面的狀況下,實現局部更新頁面。可是瀏覽器處於對安全方面的考慮,不容許跨域調用其餘頁面的對象。
其實這個也不能怪瀏覽器,假設誰均可以隨隨便便向你發送請求,那樣有很大的安全隱患。
根據瀏覽器的同源策略, 只有當協議,域名,端口相同的時候纔算是同源, 反之則均視爲是一個跨域的請求.
也就是說我剛剛的Vue端口是8081,服務端端口是8080,端口不同,由於同源策略的存在 ,全部個人請求會失敗。前端

一個問題,當找到了緣由,這個問題就解決了一半了。

怎麼解決跨域

下面就先介紹三種跨全域的方法:node

JSONP

應該是最多見解決跨域的方法了,
他爲何能解決跨域呢,是由於Web 頁面上調用 js 文件不受瀏覽器同源策略的影響,因此經過 Script 便籤能夠進行跨域的請求:jquery

  1. 首先前端先設置好回調函數,並將其做爲 url 的參數。
  2. 服務端接收到請求後,經過該參數得到回調函數名,並將數據放在參數中將其返回
  3. 收到結果後由於是 script 標籤,因此瀏覽器會當作是3腳本進行運行,從而達到跨域獲取數據的目的。

個人前端是index.html,後端是server.js
後端邏輯:ios

//server.js
const url = require('url');
const http = require('http');

http.createServer((req, res)=>{
const data = {
    x: 10//返回的數據
};
const callback = url.parse(req.url, true).query.callback;
res.writeHead(200);
res.end(`${callback}(${JSON.stringify(data)})`);
//執行回調函數,返回data
}).listen(3000, 'localhost');

console.log('啓動服務,監聽 localhost:3000');

而後使用node server.js運行
前端:ajax

//index.html
<body>
    <script>
    function jsonpCallback(data) {
        console.log('得到 X 數據:' + data.x);
    }
    </script>
    <script src="http://localhost:3000?callback=jsonpCallback"></script>
</body>

以後打開index.html;就能夠在控制檯看到返回的數據了:
341552556856_.pic.jpgnpm

至此,經過 JSONP 跨域獲取數據已經成功了,jsonp這種方法跨域,他的兼容性很好,能夠在古老的瀏覽器中國使用,由於這種方法是利用了<script>標籤的特殊性,全部只支持GET請求。json

CORS

CORS 是一個 W3C 標準,全稱是"跨域資源共享"(Cross-origin resource sharing)它容許瀏覽器向跨源服務器,發出 XMLHttpRequest 請求,從而克服了 ajax 只能同源使用的限制。axios

CORS 須要瀏覽器和服務器同時支持才能夠生效,對於開發者來講,CORS 通訊與同源的 ajax 通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現 ajax 請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。segmentfault

所以,實現 CORS 通訊的關鍵是服務器。只要服務器實現了 CORS 接口,就能夠跨源通訊。

前端:

<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script>
$.ajax({
    url:"http://127.0.0.1:3000",
    success:function(res){
        var res = JSON.parse(res);
        $('body').text(res.data);
        console.log(res.data);
    }
});
</script>

此次前端啓動須要使用node-server來啓動,使用npm install node-server下載,而後當前目錄下使用node-server就能夠了
後端:

const http = require('http');

http.createServer((req, res)=>{
const data = {
    'data': 'Hello world'//返回的數據
};
res.writeHead(200, {'Access-Control-Allow-Origin': 'http://127.0.0.1:8080'});
//設置的頭部信息須要和前端請求的地址一致
res.end(JSON.stringify(data));
//返回data
}).listen(3000, '127.0.0.1');

console.log('啓動服務,監聽 127.0.0.1:3000');

使用命令node server.js啓動;
211552638161_.pic_hd.jpg

CORS與JSONP的使用目的相同,可是比JSONP更強大。

JSONP只支持GET請求,CORS支持全部類型的HTTP請求。JSONP的優點在於支持老式瀏覽器,以及能夠向不支持CORS的網站請求數據。

Server Proxy

服務器代理,顧名思義,當你須要有跨域的請求操做時發送請求給後端,讓後端幫你代爲請求,而後最後將獲取的結果發送給你。

假設有這樣的一個場景,你的頁面須要獲取 CNode:Node.js專業中文社區 論壇上一些數據,如經過 https://cnodejs.org/api/v1/topics,當時由於不一樣域,因此你能夠將請求後端,讓其對該請求代爲轉發。

後端代碼以下:

const url = require('url');
const http = require('http');
const https = require('https');

http.createServer((req, res)=>{
const path = url.parse(req.url).path.slice(1);
//覈對請求路由是否一致
if(path === 'topics'){
    https.get('https://cnodejs.org/api/v1/topics', (resp)=>{
        //https代發請求
        let data='';
        resp.on('data', chunk=>{
            data+= chunk
        });
        resp.on('end', ()=>{
            res.writeHead(
                200,
                {'Content-Type': 'application/json; charset=utf-8'}
            );
            res.end(data);
            //返回數據
        })
    })
}

}).listen(3000, '127.0.0.1');

console.log('啓動服務,監聽 127.0.0.1:3000');

前端代碼:

<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script>
$.ajax({
    url:"https://cnodejs.org/api/v1/topics",
    success:function(res){
        $('body').text(JSON.stringify(res));
        console.log(res);
    }
});
</script>

這樣就成功了
221552639459_.pic_hd.jpg

總結

經常使用的跨域方式基本就是這三種:

  1. JSONP

優勢是能夠兼容老瀏覽器,缺點是隻能發送GET請求

  1. CORS

優勢簡單方便,支持post請求,缺點是須要後端的配合,不支持老版瀏覽器。。

  1. Server Proxy

優勢是前端正常發送ajax請求,缺點是後端會二次請求。

其餘的跨域方式還有:location.hashwindow.namepostMessage等方式,有時間也能夠了解一下。

參考資料:

相關文章
相關標籤/搜索