日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
前端開發(fā)|那些年曾談起的跨域

對(duì)于前端開發(fā)來說跨域應(yīng)該是最不陌生的問題了,無論是開發(fā)過程中還是在面試過程中都是一個(gè)經(jīng)常遇到的一個(gè)問題,在開發(fā)過程中遇到這個(gè)問題的話一般都是找后端同學(xué)去解決,以至于很多人都忽略了對(duì)跨域的認(rèn)識(shí)。為什么會(huì)導(dǎo)致跨域?遇到跨域又怎么去解決呢?本文會(huì)對(duì)這些問題一一的介紹。

創(chuàng)新互聯(lián)從2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都做網(wǎng)站、成都網(wǎng)站制作網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元麻山做網(wǎng)站,已為上家服務(wù),為麻山各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792

在JavaScript中,在不同的域名下面進(jìn)行數(shù)據(jù)交互,就會(huì)遇到跨域問題,說到跨域首先要從同源說起,瀏覽器為了提供一種安全的運(yùn)行環(huán)境,各個(gè)瀏覽器廠商協(xié)定使用同源策略。

什么同源策略

同源策略:同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響??梢哉fWeb是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。

同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSRF等攻擊。所謂同源是指協(xié)議+域名+端口三者相同,即便兩個(gè)不同的域名指向同一個(gè)ip地址,也非同源。

Url組成部分

了解同源策略以后,同樣需要對(duì)url的組成部分也順帶了解一下吧,只有了解url之后當(dāng)出現(xiàn)跨域的時(shí)候才知道哪里出了問題,這樣才能和后端、運(yùn)維開懟,懟天懟地對(duì)空氣。O(∩_∩)O哈哈~

從上圖中能夠清晰的看出url中每個(gè)部分的含義:

  1. protocol:協(xié)議常用的協(xié)議是http
  2. auth:驗(yàn)證,因?yàn)槊魑膫鬏斢脩裘兔艽a,非HTTPS環(huán)境下很不安全,一般用的非常少
  3. hostname:主機(jī)地址,可以是域名,也可以是IP地址
  4. port:端口http協(xié)議默認(rèn)端口是:80端口,如果不寫默認(rèn)就是:80端口
  5. pathname:路徑網(wǎng)絡(luò)資源在服務(wù)器中的指定路徑
  6. serarch:查詢字符串如果需要從服務(wù)器那里查詢內(nèi)容,在這里編輯
  7. hash:哈希網(wǎng)頁中可能會(huì)分為不同的片段,如果想訪問網(wǎng)頁后直接到達(dá)指定位置,可以在這部分設(shè)置

項(xiàng)目過程過程中經(jīng)常會(huì)用到一些緩存,瀏覽器為了網(wǎng)頁的安全在緩存的時(shí)候,由于同源策略的問題對(duì)其緩存內(nèi)容進(jìn)行了限制,其實(shí)想想也是對(duì)的,如果不使用同源策略的話,很容易沖掉緩存的東西。

  1. Cookie、LocalStorage和IndexDB等無法讀取。
  2. DOM無法獲得。
  3. AJAX請(qǐng)求不能發(fā)送。

當(dāng)然瀏覽器也沒有把所有的東西都限制了,比如圖片、互聯(lián)網(wǎng)資源等還是允許跨域請(qǐng)求的。允許跨域請(qǐng)求都是使用標(biāo)簽,只有三個(gè)標(biāo)簽是允許跨域加載資源:

  1.   
  2.   
  3.   

http://localhost:7000/b.html 

 
 
 
 
  1.   
  2.   
  3.   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   

http://localhost:6000/c.html 

 
 
 
 
  1.   
  2.   
  3.   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   

a.html中有一個(gè)隱藏的iframe,該iframe指向異域http://localhost:7000/b.html的b.html,且傳遞hash值給b.html`b.html獲取hash值,生成data值,然后動(dòng)態(tài)創(chuàng)建iframe,該iframe將data值傳給與a.html同域的c.html 因?yàn)閏.html與a.html`同域,可以傳值固然也就解決了跨域問題。

window.name

window.name這個(gè)屬性不是一個(gè)簡(jiǎn)單的全局屬性只要在一個(gè)window下,無論url怎么變化,只要設(shè)置好了window.name,那么后續(xù)就一直都不會(huì)改變,同理,在iframe中,即使url在變化,iframe中的window.name也是一個(gè)固定的值,利用這個(gè),我們就可以實(shí)現(xiàn)跨域了。

http://localhost:6000/a.html 

 
 
 
 
  1.   
  2.   

http://localhost:7000/b.html 

 
 
 
 
  1. var person = {  
  2.   name: 'Aaron',  
  3.   age: 18  
  4. }  
  5. window.name = JSON.stringify(person)  

http://localhost:6000/proxy.html 

 
 
 
 
  1.   
  2.   
  3.   
  4.   
  5. proxy  
  6.   
  7.   
  8. 這是proxy頁面

      
  9.   
  10.   

在http://localhost:6000下有一個(gè)a.html,在http://localhost:7000下有一個(gè)b.html,在http://localhost:6000/a.html中創(chuàng)建了一個(gè)iframe標(biāo)簽并把地址指向了http://localhost:7000/b.html,在b.html中的window.name賦值保存了一段數(shù)據(jù),但是現(xiàn)在還獲取不了,因?yàn)槭强缬虻?,所以,我們可以把src設(shè)置為當(dāng)前域的http://localhost:6000/proxy.html,雖然域名改變了但是window.name是沒有改變的。這樣就可以拿到我們想要的數(shù)據(jù)了。

postMessage(HTML5)

可能很多不知道postMessage整個(gè)API,在HTML5中新增了postMessage方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞,postMessage在很多瀏覽器中都已經(jīng)得到了良好的支持,所以可放心的使用。該方法可以通過綁定window的message事件來監(jiān)聽發(fā)送跨文檔消息傳輸內(nèi)容。

postMessage()方法接受兩個(gè)參數(shù)

   1.  data:要傳遞的數(shù)據(jù),html5規(guī)范中提到該參數(shù)可以是JavaScript的任意基本類型或可復(fù)制的對(duì)象,然而并不是所有瀏覽器都做到了這點(diǎn)兒,部分瀏覽器只能處理字符串參數(shù),所以我們?cè)趥鬟f參數(shù)的時(shí)候需要使用JSON.stringify()方法對(duì)對(duì)象參數(shù)序列化,在低版本IE中引用json2.js可以實(shí)現(xiàn)類似效果。

   1.  origin:字符串參數(shù),指明目標(biāo)窗口的源,協(xié)議+主機(jī)+端口號(hào)+URL,URL會(huì)被忽略,所以可以不寫,這個(gè)參數(shù)是為了安全考慮,postMessage()方法只會(huì)將message傳遞給指定窗口,當(dāng)然如果愿意也可以建參數(shù)設(shè)置為"*",這樣可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"。

http://localhost:6000/a.html 

 
 
 
 
  1.   
  2.   
  3.   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.       
  10.     發(fā)送消息  
  
  •   
  •   
  •   
  •   
  • http://localhost:7000/b.html 

     
     
     
     
    1.   
    2.   
    3.   
    4.   
    5.   
    6.   
    7.   
    8.   
    9.     Hello World!  
      
  •   
  •   
  •   
  • 這樣我們就可以接收任何窗口傳遞來的消息了,為了安全起見,我們利用這時(shí)候的MessageEvent對(duì)象判斷了一下消息源,MessageEvent對(duì)象,這個(gè)對(duì)象中包含很多東西。

    1. data:顧名思義,是傳遞來的message
    2. source:發(fā)送消息的窗口對(duì)象
    3. origin:發(fā)送消息窗口的源(協(xié)議+主機(jī)+端口號(hào))

    使用postMessage方法比以上方法用起來要輕便,不必有太多的繁瑣操作,可以說postMessage是對(duì)于解決跨域來說是一個(gè)比較好的解決方案,不會(huì)顯得代碼特別的臃腫,并且各個(gè)瀏覽器又有良好的支持。

    跨域資源共享(CORS)

    CORS:全稱"跨域資源共享"(Cross-origin resource sharing)。CORS需要瀏覽器和服務(wù)器同時(shí)支持,才可以實(shí)現(xiàn)跨域請(qǐng)求,目前幾乎所有瀏覽器都支持CORS,IE則不能低于IE10。CORS的整個(gè)過程都由瀏覽器自動(dòng)完成,前端無需做任何設(shè)置,跟平時(shí)發(fā)送ajax請(qǐng)求并無差異。CORS的關(guān)鍵在于服務(wù)器,只要服務(wù)器實(shí)現(xiàn)CORS接口,就可以實(shí)現(xiàn)跨域通信。

    跨域資源共享(CORS) 是一種機(jī)制,它使用額外的HTTP頭來告訴瀏覽器讓運(yùn)行在一個(gè)origin (domain) 上的Web應(yīng)用被準(zhǔn)許訪問來自不同源服務(wù)器上的指定的資源。當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器不同的域、協(xié)議或端口請(qǐng)求一個(gè)資源時(shí),資源會(huì)發(fā)起一個(gè)跨域HTTP請(qǐng)求。在上面說過src是不受同源策略限制的,但是出于安全原因,瀏覽器限制從腳本內(nèi)發(fā)起的跨源HTTP請(qǐng)求。例如,XMLHttpRequest和FetchAPI遵循同源策略。這意味著使用這些API的Web應(yīng)用程序只能從加載應(yīng)用程序的同一個(gè)域請(qǐng)求HTTP資源,除非響應(yīng)報(bào)文包含了正確CORS響應(yīng)頭。

    所有CORS相關(guān)的的頭都是Access-Control為前綴的。下面是每個(gè)頭的一些細(xì)節(jié)。

    字段 描述
    Access-Control-Allow-Methods該字段必需,它的值是逗號(hào)分隔的一個(gè)字符串,表明服務(wù)器支持的所有跨域請(qǐng)求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請(qǐng)求的那個(gè)方法。這是為了避免多次"預(yù)檢"請(qǐng)求
    Access-Control-Allow-Headers如果瀏覽器請(qǐng)求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個(gè)逗號(hào)分隔的字符串,表明服務(wù)器支持的所有頭信息字段,不限于瀏覽器在"預(yù)檢"中請(qǐng)求的字段
    Access-Control-Allow-Credentials該字段與簡(jiǎn)單請(qǐng)求時(shí)的含義相同。
    Access-Control-Max-Age該字段可選,用來指定本次預(yù)檢請(qǐng)求的有效期,單位為秒。上面結(jié)果中,有效期是20天(1728000秒),即允許緩存該條回應(yīng)1728000秒(即20天),在此期間,不用發(fā)出另一條預(yù)檢請(qǐng)求。

     

     
     
     
     
    1. import express from "express";  
    2. import cors from "cors";  
    3. const app = express()  
    4. const  
    5. var corsOptions = {  
    6.   origin: 'http://example.com',  
    7.   optionsSuccessStatus: 200  
    8. }  
    9. app.get('/products/:id', cors(corsOptions), (req, res, next) => {  
    10.   res.json({msg: 'This is CORS-enabled for only example.com.'})  
    11. })  
    12. app.listen(80, function () {  
    13.   console.log('啟用corba,端口:80')  
    14. })  

    使用CORS簡(jiǎn)單請(qǐng)求,非常容易,對(duì)于前端來說無需做任何配置,與發(fā)送普通ajax請(qǐng)求無異。唯一需要注意的是,需要攜帶cookie信息時(shí),需要將withCredentials設(shè)置為true即可。CORS的配置,完全在后端設(shè)置,配置起來也比較容易,目前對(duì)于大部分瀏覽器兼容性也比較好,現(xiàn)在應(yīng)用最多的就是CORS解決跨域了。

    WebSocket協(xié)議跨域

    WebSocket是HTML5新推出的一個(gè)API,通過WebSocket可以實(shí)現(xiàn)客戶端與服務(wù)端的即時(shí)通信,如聊天室,服務(wù)數(shù)據(jù)同步渲染等等。WebSocket是點(diǎn)對(duì)點(diǎn)通信,服務(wù)端與客戶端可以通過某種標(biāo)識(shí)完成的。WebSocket是不受同源策略限制的所以可以利用這個(gè)特性直接與服務(wù)端進(jìn)行點(diǎn)對(duì)點(diǎn)通信。

    以下示例沒有使用HTML5的WebSocket而是使用的socket.io完成類似的功能操作。

    若若的說一句:其實(shí)我一直以為WebSocket與Ajax一樣是受同源策略限制的,經(jīng)過學(xué)習(xí)才發(fā)現(xiàn)不是的。真是學(xué)到老活到老(關(guān)谷口音)。O(∩_∩)O

    服務(wù)端: 

     
     
     
     
    1. var io = require('socket.io')(1234);  
    2. io.sockets.on('connection', (client) => {  
    3.     client.on('message', function (msg) { //監(jiān)聽到信息處理  
    4.         client.send('服務(wù)器收到了信息:' + msg);  
    5.     });  
    6.     client.on("disconnect", function () { //斷開處理  
    7.         console.log("client has disconnected");  
    8.     });  
    9. });  
    10. console.log("listen 1234...");  

    客戶端: 

     
     
     
     
    1. $(function () {  
    2.     var ioiosocket = io.connect('http://localhost:1234/');  
    3.     var $ul = $("ul");  
    4.     var $input = $("input");  
    5.     iosocket.on('connect', function () {  //接通處理  
    6.         $ul.append($('
    7. 連上啦
    8. '));  
    9.         iosocket.on('message', function (message) {  //收到信息處理  
    10.             $ul.append($('
    11. ').text(message));  
    12.         });  
    13.         iosocket.on('disconnect', function () { //斷開處理  
    14.             $ul.append('
    15. Disconnected
    16. ');  
    17.         });  
    18.     });  
    19.     $input.keypress(function (event) {  
    20.         if (event.which == 13) { //回車  
    21.             event.preventDefault();  
    22.             console.log("send : " + $input.val());  
    23.             iosocket.send($input.val());  
    24.             $input.val('');  
    25.         }  
    26.     });  
    27. });  

    Websocket既然能支持跨域方法,那就是說,一個(gè)開放給公網(wǎng)的Websocket服務(wù)任何人都能訪問,這樣的話會(huì)使數(shù)據(jù)變得很不安全,所以可以通過對(duì)連接域名進(jìn)行認(rèn)證即可。

    服務(wù)器反代

    學(xué)習(xí)路程首先了解了一下什么是反代,在計(jì)算機(jī)網(wǎng)絡(luò)中,反向代理是代理服務(wù)器的一種。服務(wù)器根據(jù)客戶端的請(qǐng)求,從其關(guān)聯(lián)的一組或多組后端服務(wù)器(如Web服務(wù)器)上獲取資源,然后再將這些資源返回給客戶端,客戶端只會(huì)得知反向代理的IP地址,而不知道在代理服務(wù)器后面的服務(wù)器簇的存在。 -- 節(jié)選自百度百科

    反向代理服務(wù)器:就nginx把http請(qǐng)求轉(zhuǎn)發(fā)到另一個(gè)或者一些服務(wù)器上。從而輕松實(shí)現(xiàn)跨域訪問。比如服務(wù)器中分別部署了N個(gè)服務(wù)器,當(dāng)客戶端發(fā)起請(qǐng)求時(shí)不用直接請(qǐng)求服務(wù)器中N個(gè)節(jié)點(diǎn)上的服務(wù),只需要訪問我們的代理服務(wù)器就行了,代理服務(wù)器根據(jù)請(qǐng)求內(nèi)容分發(fā)到不同服務(wù)器節(jié)點(diǎn)。這僅是一種使用場(chǎng)景,當(dāng)然還可以做負(fù)載均衡等。

    反向代理理解起來不是特別的難,平時(shí)生活中最常見的例子,當(dāng)我們撥打人工客服的時(shí)候,并不是直接撥打客服的某一個(gè)電話號(hào)碼,而是撥打總機(jī)號(hào)碼,當(dāng)我們撥打然后由總機(jī)進(jìn)行處理,然后再分發(fā)給不同的客服人員。r然而當(dāng)服務(wù)人員需要讓你掛斷電話等待回?fù)艿臅r(shí)候,也不是直接撥打到你的電話,同樣是也通過總機(jī)之后再轉(zhuǎn)發(fā)到你的電話。其實(shí)這個(gè)總機(jī)也就相當(dāng)于反代服務(wù)器。雖然這個(gè)例子不太貼切但是多多少少就是這個(gè)意思。

    由于不太懂Nginx不知道該如何處理這個(gè)部分,只是對(duì)反向代理做了一個(gè)簡(jiǎn)單的了解,等以后學(xué)習(xí)了Nginx會(huì)補(bǔ)上相關(guān)代碼。

    Nodejs代理跨域

    使用Nodejs進(jìn)行跨域在我看來,就是使用Node服務(wù)做了一個(gè)中間代理轉(zhuǎn)發(fā),其原理和反向代理差不多,當(dāng)訪問某一個(gè)URL時(shí)需要通過服務(wù)器分發(fā)到另一個(gè)服務(wù)器URL地址中。這里就不過多的贅述了,直接看代碼吧。

    示例代碼入下:

    main.js 

     
     
     
     
    1. import http from "http";  
    2. import httpProxy from "http-proxy";  
    3. // 新建一個(gè)代理 Proxy Server 對(duì)象    
    4. const proxy = httpProxy.createProxyServer({});     
    5. // 捕獲異常    
    6. proxy.on('error', function (err, req, res) {    
    7.   res.writeHead(500, {    
    8.     'Content-Type': 'text/plain'    
    9.   });    
    10.   res.end('error');    
    11. });       
    12. // 在每次請(qǐng)求中,調(diào)用 proxy.web(req, res config) 方法進(jìn)行請(qǐng)求分發(fā)    
    13. const server = http.createServer((req, res) => {   
    14.   // 在這里可以自定義你的路由分發(fā)    
    15.   let host = req.headers.host, ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;    
    16.   switch(host){    
    17.     case 'www.a.com':     
    18.         proxy.web(req, res, { target: 'http://localhost:3000' });    
    19.         break;    
    20.     case 'www.b.com':    
    21.         proxy.web(req, res, { target: 'http://localhost:4000' });    
    22.         break;  
    23.     default:    
    24.         res.writeHead(200, {    
    25.             'Content-Type': 'text/plain'    
    26.         });    
    27.         res.end('Hello Aaron!');    
    28.   }    
    29. });    
    30. server.listen(8080);  

    如代碼所示,當(dāng)訪問www.a.com的時(shí)候,請(qǐng)求就被轉(zhuǎn)發(fā)到了3000接口上,訪問www.b.com時(shí)就被轉(zhuǎn)發(fā)到了4000這個(gè)接口上。這樣就簡(jiǎn)單的完成了一個(gè)反向代理的工作。

    在使用vue開發(fā)的時(shí)候難免也會(huì)遇到跨域問題,或許你根本就沒有遇到,可能你們正好處于同一個(gè)域里面,還有一種可能就是,后端同學(xué)或者運(yùn)維同學(xué)已經(jīng)處理好有關(guān)跨域的相關(guān)操作。但是當(dāng)在開發(fā)過程中遇到跨域的時(shí)候,什么前端應(yīng)該有對(duì)應(yīng)的解決辦法。vue-cli是基于Node服務(wù)
    分享標(biāo)題:前端開發(fā)|那些年曾談起的跨域
    標(biāo)題路徑:http://www.5511xx.com/article/coipccg.html