vue2.x中的跨域

一、什么是跨域

url的組成

JavaScript出于安全方面的考慮,不允許跨域調(diào)用其他頁(yè)面的對(duì)象。那什么是跨域呢,簡(jiǎn)單地理解就是因?yàn)镴avaScript同源策略的限制,a.com域名下的js無(wú)法操作b.com或是c.a.com域名下的對(duì)象。

當(dāng)協(xié)議、子域名、主域名、端口號(hào)中任意一個(gè)不相同時(shí),都算作不同域。不同域之間相互請(qǐng)求資源,就算作“跨域”。

例如:http://www.abc.com/index.html請(qǐng)求http://www.efg.com/service.php。

有一點(diǎn)必須要注意:跨域并不是請(qǐng)求發(fā)不出去,請(qǐng)求能發(fā)出去,服務(wù)端能收到請(qǐng)求并正常返回結(jié)果,只是結(jié)果被瀏覽器攔截了。之所以會(huì)跨域,是因?yàn)槭艿搅送床呗缘南拗?,同源策略要求源相同才能正常進(jìn)行通信,即協(xié)議、域名、端口號(hào)都完全一致。


image

特別說(shuō)明兩點(diǎn):

第一:如果是協(xié)議和端口造成的跨域問(wèn)題“前臺(tái)”是無(wú)能為力的。

第二:在跨域問(wèn)題上,域僅僅是通過(guò)“URL的首部”來(lái)識(shí)別而不會(huì)根據(jù)域名對(duì)應(yīng)的IP地址是否相同來(lái)判斷。“URL的首部”可以理解為“協(xié)議, 域名和端口必須匹配”。

二、什么是同源策略及其限制

同源策略限制從一個(gè)源加載的文檔或腳本如何與來(lái)自另一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離潛在惡意文件的關(guān)鍵的安全機(jī)制。它的存在可以保護(hù)用戶隱私信息,防止身份偽造等(讀取Cookie)。

同源策略限制內(nèi)容有:

Cookie、LocalStorage、IndexedDB 等存儲(chǔ)性內(nèi)容

DOM 節(jié)點(diǎn)

AJAX 請(qǐng)求不能發(fā)送

但是有三個(gè)標(biāo)簽是允許跨域加載資源:

1.<img?src=XXX>?2.<link?href=XXX>?3.<script?src=XXX>

接下來(lái)我們討論下有哪些處理跨域的方法。但所有的跨域都必須經(jīng)過(guò)信息提供方的允許。如果未經(jīng)允許即可獲取,那是瀏覽器同源策略出現(xiàn)漏洞。

三、處理跨域方法一——JSONP

1.JSONP原理

利用<script>元素的這個(gè)開(kāi)放策略,網(wǎng)頁(yè)可以得到從其他來(lái)源動(dòng)態(tài)產(chǎn)生的 JSON 數(shù)據(jù)。JSONP請(qǐng)求一定需要對(duì)方的服務(wù)器做支持才可以。

2.JSONP和AJAX對(duì)比

JSONP和AJAX相同,都是客戶端向服務(wù)器端發(fā)送請(qǐng)求,從服務(wù)器端獲取數(shù)據(jù)的方式。但AJAX屬于同源策略,JSONP屬于非同源策略(跨域請(qǐng)求)

3.JSONP優(yōu)缺點(diǎn)

JSONP優(yōu)點(diǎn)是兼容性好,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問(wèn)的問(wèn)題。缺點(diǎn)是僅支持get方法具有局限性。

4.JSONP的流程(以第三方API地址為例,不必考慮后臺(tái)程序)

聲明一個(gè)回調(diào)函數(shù),其函數(shù)名(如fn)當(dāng)做參數(shù)值,要傳遞給跨域請(qǐng)求數(shù)據(jù)的服務(wù)器,函數(shù)形參為要獲取目標(biāo)數(shù)據(jù)(服務(wù)器返回的data)。

創(chuàng)建一個(gè)<script>標(biāo)簽,把那個(gè)跨域的API數(shù)據(jù)接口地址,賦值給script的src,還要在這個(gè)地址中向服務(wù)器傳遞該函數(shù)名(可以通過(guò)問(wèn)號(hào)傳參:?callback=fn)。

服務(wù)器接收到請(qǐng)求后,需要進(jìn)行特殊的處理:把傳遞進(jìn)來(lái)的函數(shù)名和它需要給你的數(shù)據(jù)拼接成一個(gè)字符串,例如:傳遞進(jìn)去的函數(shù)名是fn,它準(zhǔn)備好的數(shù)據(jù)是fn([{"name":"jianshu"}])。

最后服務(wù)器把準(zhǔn)備的數(shù)據(jù)通過(guò)HTTP協(xié)議返回給客戶端,客戶端再調(diào)用執(zhí)行之前聲明的回調(diào)函數(shù)(fn),對(duì)返回的數(shù)據(jù)進(jìn)行操作。

<script?type="text/javascript">???

?function?fn(data)?{??????

? alert(data.msg);???

?}

</script>

?<script?type="text/javascript"?src="http://crossdomain.com/jsonServerResponse?jsonp=fn"></script>

其中 fn 是客戶端注冊(cè)的回調(diào)的函數(shù),目的獲取跨域服務(wù)器上的json數(shù)據(jù)后,對(duì)數(shù)據(jù)進(jìn)行在處理。

最后服務(wù)器返回給客戶端數(shù)據(jù)的格式為:

fn({?msg:'this??is??json??data'})

5.jQuery的jsonp形式

JSONP都是GET和異步請(qǐng)求的,不存在其他的請(qǐng)求方式和同步請(qǐng)求,且jQuery默認(rèn)就會(huì)給JSONP的請(qǐng)求清除緩存。

$.ajax({

url:"http://crossdomain.com/jsonServerResponse",

dataType:"jsonp",

type:"get",//可以省略

?jsonpCallback:"fn",//->自定義傳遞給服務(wù)器的函數(shù)名,而不是使用jQuery自動(dòng)生成的,可省略

jsonp:"jsonp",//->把傳遞函數(shù)名的那個(gè)形參callback變?yōu)閖sonp,可省略

success:function?(data){

console.log(data)

;}

?});

四、處理跨域方法二——CORS

1.CORS原理

整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺(jué)。因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。

2.CORS優(yōu)缺點(diǎn)

CORS要求瀏覽器(>IE10)和服務(wù)器的同時(shí)支持,是跨域的根本解決方法,由瀏覽器自動(dòng)完成

優(yōu)點(diǎn)在于功能更加強(qiáng)大支持各種HTTP Method,缺點(diǎn)是兼容性不如JSONP。

只需要在服務(wù)器端做一些小小的改造即可:

header("Access-Control-Allow-Origin:*");

?header("Access-Control-Allow-Methods:POST,GET");

例如:網(wǎng)站http://localhost:63342/頁(yè)面要請(qǐng)求http://localhost:3000/users/userlist頁(yè)面,userlist頁(yè)面返回json字符串格{name: 'Mr.Cao', gender: 'male', career: 'IT Education'}

//在服務(wù)器端設(shè)置同源策略地址?router.get("/userlist",?function?(req,?res,?next)?{?????

?????? var?user?=?{name:?'Mr.Cao',?gender:?'male',?career:?'IT?Education'};

?????? res.writeHeader(200,{"Access-Control-Allow-Origin":'http://localhost:63342'});

?????? res.write(JSON.stringify(user));

?????? res.end();

?? });

在響應(yīng)頭上添加Access-Control-Allow-Origin屬性,指定同源策略的地址。同源策略默認(rèn)地址是網(wǎng)頁(yè)的本身。只要瀏覽器檢測(cè)到響應(yīng)頭帶上了CORS,并且允許的源包括了本網(wǎng)站,那么就不會(huì)攔截請(qǐng)求響應(yīng)。

五、處理跨域方法三——WebSocket

Websocket是HTML5的一個(gè)持久化的協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器的全雙工通信,同時(shí)也是跨域的一種解決方案。WebSocket和HTTP都是應(yīng)用層協(xié)議,都基于 TCP 協(xié)議。但是 WebSocket 是一種雙向通信協(xié)議,在建立連接之后,WebSocket 的 server 與 client 都能主動(dòng)向?qū)Ψ桨l(fā)送或接收數(shù)據(jù)。同時(shí),WebSocket 在建立連接時(shí)需要借助 HTTP 協(xié)議,連接建立好了之后 client 與 server 之間的雙向通信就與 HTTP 無(wú)關(guān)了。

原生WebSocket API使用起來(lái)不太方便,我們使用Socket.io,它很好地封裝了webSocket接口,提供了更簡(jiǎn)單、靈活的接口,也對(duì)不支持webSocket的瀏覽器提供了向下兼容。

//前端代碼:

<div>user?input:<input?type="text"></div>

?<script?src="./socket.io.js"></script>

?<script>?var?socket?=?io('http://www.domain2.com:8080');

?//?連接成功處理

socket.on('connect',?function()?{???

?//?監(jiān)聽(tīng)服務(wù)端消息???

?socket.on('message',?function(msg)?{

??????? console.log('data?from?server:?--->?'?+?msg);

????? });?

//?監(jiān)聽(tīng)服務(wù)端關(guān)閉????

socket.on('disconnect',?function()?{

???????? console.log('Server?socket?has?closed.');

????? });

?});

?document.getElementsByTagName('input')[0].onblur?=?function()?{

??? socket.send(this.value);

};

</script>

//Nodejs?socket后臺(tái):

var?http?=?require('http');

var?socket?=?require('socket.io');

?//?啟http服務(wù)

var?server?=?http.createServer(function(req,?res)?{

???? res.writeHead(200,?{

??????? 'Content-type':?'text/html'

??? });

??? res.end();

?});

server.listen('8080');

console.log('Server?is?running?at?port?8080...');

?//?監(jiān)聽(tīng)socket連接

socket.listen(server).on('connection',?function(client)?{

??? //?接收信息

?client.on('message',?function(msg)?{

???????? client.send('hello:'?+?msg);

???????? console.log('data?from?client:?--->?'?+?msg);

???? });

??? //?斷開(kāi)處理

???? client.on('disconnect',?function()?{

???????? console.log('Client?socket?has?closed.');

????? });

?});

六、處理跨域方法四——postMessage

如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM。典型的例子是iframe窗口和window.open方法打開(kāi)的窗口,它們與父窗口無(wú)法通信。HTML5為了解決這個(gè)問(wèn)題,引入了一個(gè)全新的API:跨文檔通信 API(Cross-document messaging)。這個(gè)API為window對(duì)象新增了一個(gè)window.postMessage方法,允許跨窗口通信,不論這兩個(gè)窗口是否同源。postMessage方法的第一個(gè)參數(shù)是具體的信息內(nèi)容,第二個(gè)參數(shù)是接收消息的窗口的源(origin),即"協(xié)議 + 域名 + 端口"。也可以設(shè)為*,表示不限制域名,向所有窗口發(fā)送。

接下來(lái)我們看個(gè)例子:

http://localhost:63342/index.html頁(yè)面向http://localhost:63342/index.html傳遞“跨域請(qǐng)求信息”

//發(fā)送信息頁(yè)面

?http://localhost:63342/index.html

<html?lang="en">

? <head>

?????? <meta?charset="UTF-8">

?????? <title>跨域請(qǐng)求</title>

??? </head>

?? <body>

?????? <iframe?src="http://localhost:3000/users/reg"?id="frm"></iframe>

????? <input?type="button"?value="OK"?onclick="run()">

?? </body>

?? </html>

?? <script>

????? function??run(){

???????? var?frm=document.getElementById("frm");

????????? frm.contentWindow.postMessage("跨域請(qǐng)求信息","http://localhost:3000");

????? }

?? </script>

//接收信息頁(yè)面

http://localhost:3000/message.html

?window.addEventListener("message",function(e){

?//通過(guò)監(jiān)聽(tīng)message事件,可以監(jiān)聽(tīng)對(duì)方發(fā)送的消息。??

console.log(e.data);?

?},false);



vue跨域

1、fetch

App.vue

//跨域請(qǐng)求處理

created(){

//fetch

fetch("/apis/server_new/login",{

method:"post",

header:{

// "Content-type":"application/json",

token:"54cas56156d4a6s1das1d6sa4d6a51d65asd"

},

body:JSON.stringify({username:"admin",password:"123456"})

})

.then(result=>{

// console.log(result)

return result.json()

})

.then(data=>{

console.log(data)

})

}

在config/index.js

// Paths

? ? assetsSubDirectory: 'static',

? ? assetsPublicPath: '/',

? ? proxyTable: {

? ? '/apis': {? ? //將www.exaple.com印射為/apis

? ? ? ? ? ? target: 'https://www.exaple.com',? // 接口域名

? ? ? ? ? ? secure: false,? // 如果是https接口,需要配置這個(gè)參數(shù)

? ? ? ? ? ? changeOrigin: true,? //是否跨域

? ? ? ? ? ? pathRewrite: {

? ? ? ? ? ? ? ? '^/apis': ''? //需要rewrite重寫(xiě)的,

? ? ? ? ? ? }? ? ? ? ? ? ?

? ? ? ? }

? ? },


重啟:必須重啟

2、axios

安裝axios

npm install acios

引入axios

import axios from 'axios'

Vue.prototype.$axios=axios

實(shí)現(xiàn)

//axios

this.$axios.post("/apis/server_new/login",{username:"admin",password:"123456"})

.then(data=>{

console.log(data)

})

設(shè)置token

axios.defaults.header.common['token']="5sad5as5da5as5d5asd564d5"

axios.defaults.header.post['Content-type']="application/json"

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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