您好,登錄后才能下訂單哦!
本篇內容介紹了“分析web前端開發中跨域問題”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
什么同源策略
同源策略:同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源策略是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSRF等攻擊。所謂同源是指協議+域名+端口三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。
Url組成部分
了解同源策略以后,同樣需要對url的組成部分也順帶了解一下吧,只有了解url之后當出現跨域的時候才知道哪里出了問題,這樣才能和后端、運維開懟,懟天懟地對空氣。O(∩_∩)O哈哈~
從上圖中能夠清晰的看出url中每個部分的含義:
鴻蒙官方戰略合作共建——HarmonyOS技術社區
protocol:協議常用的協議是http
auth:驗證,因為明文傳輸用戶名和密碼,非HTTPS環境下很不安全,一般用的非常少
hostname:主機地址,可以是域名,也可以是IP地址
port:端口http協議默認端口是:80端口,如果不寫默認就是:80端口
pathname:路徑網絡資源在服務器中的指定路徑
serarch:查詢字符串如果需要從服務器那里查詢內容,在這里編輯
hash:哈希網頁中可能會分為不同的片段,如果想訪問網頁后直接到達指定位置,可以在這部分設置
項目過程過程中經常會用到一些緩存,瀏覽器為了網頁的安全在緩存的時候,由于同源策略的問題對其緩存內容進行了限制,其實想想也是對的,如果不使用同源策略的話,很容易沖掉緩存的東西。
鴻蒙官方戰略合作共建——HarmonyOS技術社區
Cookie、LocalStorage和IndexDB等無法讀取。
DOM無法獲得。
AJAX請求不能發送。
當然瀏覽器也沒有把所有的東西都限制了,比如圖片、互聯網資源等還是允許跨域請求的。允許跨域請求都是使用標簽,只有三個標簽是允許跨域加載資源:
鴻蒙官方戰略合作共建——HarmonyOS技術社區
<img src=XXX>
<link href=XXX>
<script src=XXX>
在項目開發過程中時不時的就會遇到下面這樣拋出了錯誤,有的人可能在開發過程中沒有遇到過,如果是的話,你可能遇到一個很不錯的后端或者運維。
XMLHttpRequest cannot loadhttp://www.******.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
上面的報錯就是典型的跨域報錯,既然跨域這么常見到底都有哪些情況會導致跨域的問題:
說明 | 是否允許通信 |
---|---|
同一域名下 | 允許 |
同一域名下不同文件夾 | 允許 |
同一域名,不同端口 | 不允許 |
同一域名,不同協議 | 不允許 |
域名和域名對應ip | 不允許 |
主域名相同,子域名不同 | 不允許 |
同一域名,不同二級域名 | 不允許 |
不同域名 | 不允許 |
跨域解決方案
由于瀏覽器的限制造成了很多的跨域問題,同樣也是為了安全,既然出現了跨域就必定要有一些對應的解決方案,總不能遇到跨域之后項目就不做了啊,可能瞬間就涼了。閑話就不多扯了。
JSONP
在遇到跨域的時候經常會提及到的一個詞就是JSONP,一直在說JSONP?可是通過什么原理來實現的呢?我覺得應該了解一下到底什么再去了解一下實現固然原理也就懂得咯。
什么是JSONP
JSONP:JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數據訪問的問題。由于同源策略,一般來說位于server1.example.com的網頁無法與不是server1.example.com的服務器溝通,而HTML的<script>元素是一個例外。利用<script>元素的這個開放策略,網頁可以得到從其他來源動態產生的JSON資料,而這種使用模式就是所謂的JSONP。用JSONP抓到的資料并不是JSON,而是任意的JavaScript,用JavaScript直譯器執行而不是用JSON解析器解析。 - 選自百度百科
對于JSONP簡單的百度了一下,百度給出的解釋如上,看完整段話,有一些小的收獲,第一script標簽具有開放策略,可以使用src的開放性解決其跨域問題。在這里簡單的闡述一下個人觀點。JSONP可以分為兩個部分來解讀,JSON與padding,JSON固然就不用解釋了,只是一種數據格式,padding在css中是內填充的意思,其實JSONP的原理與內填充有些類似。通過把數據填充js文件中然后引入到頁面中,并在頁面中使用。
有沒有注意過百度,其實百度的即時搜索就是使用JSONP來實現的,可以嘗試一下,在百度中搜索一下,就會在Network中看到一個以sugrec為開頭的請求,這個請求就是使用的JSONP的形式,為了大家方便特意截選了一個段連接。
連接: https://www.baidu.com/sugrec?prod=pc&wd=json&pwd=json&cb=query 返回格式: query({ "q": "json", "p": false, "g": [{ "type": "sug", "sa": "s_1", "q": "json格式" }, { "type": "sug", "sa": "s_2", "q": "jsonp" }, { "type": "sug", "sa": "s_3", "q": "json解析" }, ...] })
通過對百度的即時搜索的分析就可以簡單的看出JSONP的實現原理,請求會的js文件中包含一個函數,其函數名稱就是連接中cb的參數最為參數傳給后臺,后臺通過處理并在執行這個與參數對應的函數的,當函數執行的時候將把數據以實參的形式傳遞給對應的函數,解決跨域問題。為了方便閱讀這里只截取了代碼片段。
案例:
前端代碼:
$('#btn').click(function(){ var frame = document.createElement('script'); frame.src = 'http://localhost:5000/jsonp?name=aaron&age=18&callback=query'; $('body').append(frame); }); function query(res){ console.log(res.message+res.name+'你已經'+res.age+'歲了'); }
后端代碼:
router.get('/jsonp', (req, res) => { let {name,age,callback} = req.query; let data = {message:'success',name,age}; data = JSON.stringify(data); res.end(`${callback}(${data})`); });
通過如上代碼就可以簡單的實現JSONP,雖然JSONP解決了跨域的問題,還是有很多弊端的,比如會在頁面中添加一些script標簽,數據不能雙向操作等等。
使用JSONP的時候尤其要注意一點,一定要把插入的script放到所應用函數的下面。這個和js的執行順序有關系,如果把script標簽放在上面的話,其方法還沒有被讀取在script標簽中就執行了這個方法必定報錯的,這點很重要哦。
document.domain
document.domain項目中一般應用的較少,默認情況下document.domain存放的是載入文檔的服務器的主機名。可以在控制臺輸出一下,得到的則是segmentfault.com這個域名。我在項目中所用到的則是結合iframe的時候遇到的跨域,并使用的domain解決的。
在使用document.domain實現跨域的時候需要注意一下,這兩個域名必須屬于同一個一級域名!而且所用的協議,端口都要一致,否則無法利用document.domain進行跨域。Javascript出于對安全性的考慮,而禁止兩個或者多個不同域的頁面進行互相操作。而相同域的頁面在相互操作的時候不會有任何問題。
簡單的解釋一下,例如想要在www.a.com中將看到segmentfault.com中的內容并將其網頁使用iframe將其嵌入到其網頁中,但是此時瀏覽器是不允許通過JavaScript直接操作segmentfault.com的,因為這兩個頁面屬于不同的域,在操作之前瀏覽器會檢測是否符合同源策略,如果符合則允許操作,反之則不行。
若想要同過document.domain實現跨域的話,必須使其滿足同源策略,這個時候就需要用到document.domain,document.domain都設成相同的域名就可以了。但要注意的是,document.domain的設置是有限制的,我們只能把document.domain設置成自身或更高一級的父域,且主域必須相同。
例如:
a.com news.a.com
news.a.com屬于a.com的一個子域名,按照上面所說已經滿足了上面的規則,如果想要實現跨域操作就需要對接子頁面的document.domain進行操作。
父頁面:
document.domain = 'a.com'; var ifr = document.createElement('iframe'); ifr.src = 'news.a.com/map.html'; ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; var oUl = doc.getElementById('ul1'); alert(oUl.innerHTML); ifr.onload = null; };
子頁面:
document.domain = 'a.com'; $ajax.get({ // ...省略 })
其實現原理就是通過iframe載入一個與你想要通過ajax獲取數據的目標頁面處在相同的域的頁面,所以這個iframe中的頁面是可以正常使用ajax去獲取你要的數據的,然后就是通過我們剛剛講得修改document.domain的方法,讓我們能通過js完全控制這個iframe,這樣我們就可以讓iframe去發送ajax請求,然后收到的數據我們也可以獲得了。
location.hash
若理解了document.domain實現跨域原理,那么location.hash也就很號理解了,其原理與document.domain很相似一樣都是動態插入一個iframe,然后把iframe的src指向服務端地址,而服務端同樣都是輸出一段JavaScript代碼,同樣都是利用和子窗口之間的通信完成數據傳輸,同樣要針對同源策略做出處理。
既然說到了hash到底什么是hash這里也就單獨的說一下吧,雖然很好理解,但是對于新同學來說可能還不知道hash具體是什么?
hash:一般翻譯做散列、雜湊,或音譯為哈希,是把任意長度的輸入(又叫做預映射pre-image)通過散列算法變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小于輸入的空間,不同的輸入可能會散列成相同的輸出,所以不可能從散列值來確定唯一的輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。 -- 節選自百度百科
讀完之后感覺自己整個人都不好了,有些似懂非懂的意思,我所理解的哈希是指一個過程,這個過程就是把任意長度的輸入,通過哈希算法,變換成固定長度的輸出,所輸出的稱為哈希值。這種變換是一種壓縮映射,也即哈希值所占的空間一般來說遠小于輸入值的空間,不同的輸入可能會哈希出相同的輸出(概率很小)。
哈希有如下特點:
鴻蒙官方戰略合作共建——HarmonyOS技術社區
如果兩個哈希值是不相同的(根據同一函數),那么這兩個散列值的原始輸入一定是不相同的。
如果兩個哈希值相同,兩個輸入值很可能(極大概率)是相同的,但也可能不同,這種情況稱為“哈希碰撞”
抗篡改能力:對于一個數據塊,哪怕只改動其一個比特位,其hash值的改動也會非常大。
它是一種單向函數是“非對稱”的,即它是一個從明文到密文的不可逆的映射,只有加密過程,沒有解密過程。
那么哈希在平時項目開發中有什么用途呢?可以用哈希來做什么事情?對于前端來說用到哈希最多的時候可能就是錨點定位。通過不同的哈希值定位到描點指定的元素位置上。
<a href='#1'>red</a> <a href='#2'>black</a> <a href='#3'>yellow</a> <a href='#4'>pink</a> <div id='1' style='width:500px;height:200px;background-color:red'> </div> <div id='2' style='width:500px;height:200px;background-color:black'> </div> <div id='3' style='width:500px;height:200px;background-color:yellow'> </div> <div id='4' style='width:500px;height:1200px;background-color:pink'> </div>
關于更多細節的東西不再這里贅述了,如果想要了解更多的話大家可以自行google,再說下去的話可能就跑題了。
簡單的介紹了一下哈希與哈希的用處那么又該如何使用哈希來實現跨域呢?其實很簡單,如果index頁面要獲取遠端服務器的數據,動態插入一個iframe,將iframe的src屬性指向服務端地址。這時top window和包裹這個iframe的子窗口由于同源策略的原因是不能直接通信的,所以改變子窗口的路徑就行了,將數據當做改變后的路徑的hash值加在路徑上,然后就能通信了,將數據加在index頁面地址的hash值上。index頁面監聽地址的hash值變化然后做出判斷,處理數據。
父頁面:
<iframe src="http://localhost:7000/b.html#key=1&key1=2"></iframe>
由于哈希值的改變不會改變網頁的網址的,所以服務端可以通過獲取到哈希來解析url中的參數,并把數據返回給前端即可。通過parent.location.hash去改變哈希值,然后就可以像document.domain一樣去獲取到子頁面的數據了。parent.location.hash該方法是有局限性的,在IE和Chrome中是不支持這種操作的。那么整個問題應如何解決呢?
在同域的域名下面添加一個*.html(*代表任意名)文件,然后把通過iframe把*.html引入到父頁面中,并把需要請求的接口iframe添加到*.html中去請求,這樣就可以解決了。
http://localhost:6000/a.html
<!DOCTYPE html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title>無</title> </head> <body> <script type="text/javascript"> function sendRequest(){ var ifr = document.createElement('iframe'); ifr.style.display = 'none'; ifr.src = 'http://localhost:7000/b.html#Aaron'; document.body.appendChild(ifr); } function checkHash(){ var data = location.hash?location.hash.substring(1):''; if(data) location.hash = ''; } setInterval(checkHash,1000); window.onload = sendRequest; </script> </body> </html>
http://localhost:7000/b.html
<!DOCTYPE html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title>無</title> </head> <body> <script type="text/javascript"> function checkHash(){ var data = ''; switch(location.hash){ case '#Aaron': data = 'my Aaron'; break; case '#Angie': data = 'my Angie'; break; default : break; } data && callBack('#'+data); } function callBack(hash){ var proxy = document.createElement('iframe'); proxy.style.display = 'none'; proxy.src = 'http://localhost/c.html'+hash; document.body.appendChild(proxy); } window.onload = checkHash; </script> </body> </html>
http://localhost:6000/c.html
<!DOCTYPE html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title>無</title> </head> <body> <script type="text/javascript"> parent.parent.location.hash = self.location.hash.substring(1); </script> </body> </html>
a.html中有一個隱藏的iframe,該iframe指向異域http://localhost:7000/b.html的b.html,且傳遞hash值給b.html`b.html獲取hash值,生成data值,然后動態創建iframe,該iframe將data值傳給與a.html同域的c.html 因為c.html與a.html`同域,可以傳值固然也就解決了跨域問題。
window.name
window.name這個屬性不是一個簡單的全局屬性只要在一個window下,無論url怎么變化,只要設置好了window.name,那么后續就一直都不會改變,同理,在iframe中,即使url在變化,iframe中的window.name也是一個固定的值,利用這個,我們就可以實現跨域了。
http://localhost:6000/a.html
<iframe src="http://localhost:7000/b.html" frameborder="1"></iframe> <script> var ifr = document.querySelector('iframe') ifr.style.display = 'none' var flag = 0; ifr.onload = function () { if (flag == 1) { ifr.contentWindow.close(); } else if (flag == 0) { flag = 1; ifr.contentWindow.location = 'http://localhost:6000/proxy.html'; } } </script>
http://localhost:7000/b.html
var person = { name: 'Aaron', age: 18 } window.name = JSON.stringify(person)
http://localhost:6000/proxy.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>proxy</title> </head> <body> <p>這是proxy頁面</p> </body> </html>
在http://localhost:6000下有一個a.html,在http://localhost:7000下有一個b.html,在http://localhost:6000/a.html中創建了一個iframe標簽并把地址指向了http://localhost:7000/b.html,在b.html中的window.name賦值保存了一段數據,但是現在還獲取不了,因為是跨域的,所以,我們可以把src設置為當前域的http://localhost:6000/proxy.html,雖然域名改變了但是window.name是沒有改變的。這樣就可以拿到我們想要的數據了。
postMessage(HTML5)
可能很多不知道postMessage整個API,在HTML5中新增了postMessage方法允許來自不同源的腳本采用異步方式進行有限的通信,可以實現跨文本檔、多窗口、跨域消息傳遞,postMessage在很多瀏覽器中都已經得到了良好的支持,所以可放心的使用。該方法可以通過綁定window的message事件來監聽發送跨文檔消息傳輸內容。
postMessage()方法接受兩個參數
1. data:要傳遞的數據,html5規范中提到該參數可以是JavaScript的任意基本類型或可復制的對象,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數,所以我們在傳遞參數的時候需要使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js可以實現類似效果。
1. origin:字符串參數,指明目標窗口的源,協議+主機+端口號+URL,URL會被忽略,所以可以不寫,這個參數是為了安全考慮,postMessage()方法只會將message傳遞給指定窗口,當然如果愿意也可以建參數設置為"*",這樣可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/"。
http://localhost:6000/a.html
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>無</title> </head> <body> <div> <input id="text" type="text" value="My name’s Aaron" /> <button id="send" >發送消息</button> </div> <iframe id="receiver" src="http://localhost:7000/b.html"></iframe> <script> window.onload = function() { var receiver = document.getElementById('receiver').contentWindow; var btn = document.getElementById('send'); btn.addEventListener('click', function (e) { e.preventDefault(); var val = document.getElementById('text').value; receiver.postMessage("Hello "+val+"!", "http://localhost:7000"); }); } </script> </body> </html>
http://localhost:7000/b.html
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>無</title> </head> <body> <div id="message"> Hello World! </div> <script> window.onload = function() { var messageEle = document.getElementById('message'); window.addEventListener('message', function (e) { if (e.origin !== "http://localhost:6000") { return; } messageEle.innerHTML = "從"+ e.origin +"收到消息: " + e.data; }); } </script> </body> </html>
這樣我們就可以接收任何窗口傳遞來的消息了,為了安全起見,我們利用這時候的MessageEvent對象判斷了一下消息源,MessageEvent對象,這個對象中包含很多東西。
鴻蒙官方戰略合作共建——HarmonyOS技術社區
data:顧名思義,是傳遞來的message
source:發送消息的窗口對象
origin:發送消息窗口的源(協議+主機+端口號)
使用postMessage方法比以上方法用起來要輕便,不必有太多的繁瑣操作,可以說postMessage是對于解決跨域來說是一個比較好的解決方案,不會顯得代碼特別的臃腫,并且各個瀏覽器又有良好的支持。
跨域資源共享(CORS)
CORS:全稱"跨域資源共享"(Cross-origin resource sharing)。CORS需要瀏覽器和服務器同時支持,才可以實現跨域請求,目前幾乎所有瀏覽器都支持CORS,IE則不能低于IE10。CORS的整個過程都由瀏覽器自動完成,前端無需做任何設置,跟平時發送ajax請求并無差異。CORS的關鍵在于服務器,只要服務器實現CORS接口,就可以實現跨域通信。
跨域資源共享(CORS) 是一種機制,它使用額外的HTTP頭來告訴瀏覽器讓運行在一個origin (domain) 上的Web應用被準許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域HTTP請求。在上面說過src是不受同源策略限制的,但是出于安全原因,瀏覽器限制從腳本內發起的跨源HTTP請求。例如,XMLHttpRequest和FetchAPI遵循同源策略。這意味著使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非響應報文包含了正確CORS響應頭。
所有CORS相關的的頭都是Access-Control為前綴的。下面是每個頭的一些細節。
字段 | 描述 |
---|---|
Access-Control-Allow-Methods | 該字段必需,它的值是逗號分隔的一個字符串,表明服務器支持的所有跨域請求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請求的那個方法。這是為了避免多次"預檢"請求 |
Access-Control-Allow-Headers | 如果瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限于瀏覽器在"預檢"中請求的字段 |
Access-Control-Allow-Credentials | 該字段與簡單請求時的含義相同。 |
Access-Control-Max-Age | 該字段可選,用來指定本次預檢請求的有效期,單位為秒。上面結果中,有效期是20天(1728000秒),即允許緩存該條回應1728000秒(即20天),在此期間,不用發出另一條預檢請求。 |
import express from "express"; import cors from "cors"; const app = express() const var corsOptions = { origin: 'http://example.com', optionsSuccessStatus: 200 } app.get('/products/:id', cors(corsOptions), (req, res, next) => { res.json({msg: 'This is CORS-enabled for only example.com.'}) }) app.listen(80, function () { console.log('啟用corba,端口:80') })
使用CORS簡單請求,非常容易,對于前端來說無需做任何配置,與發送普通ajax請求無異。唯一需要注意的是,需要攜帶cookie信息時,需要將withCredentials設置為true即可。CORS的配置,完全在后端設置,配置起來也比較容易,目前對于大部分瀏覽器兼容性也比較好,現在應用最多的就是CORS解決跨域了。
WebSocket協議跨域
WebSocket是HTML5新推出的一個API,通過WebSocket可以實現客戶端與服務端的即時通信,如聊天室,服務數據同步渲染等等。WebSocket是點對點通信,服務端與客戶端可以通過某種標識完成的。WebSocket是不受同源策略限制的所以可以利用這個特性直接與服務端進行點對點通信。
以下示例沒有使用HTML5的WebSocket而是使用的socket.io完成類似的功能操作。
若若的說一句:其實我一直以為WebSocket與Ajax一樣是受同源策略限制的,經過學習才發現不是的。真是學到老活到老(關谷口音)。O(∩_∩)O
服務端:
var io = require('socket.io')(1234); io.sockets.on('connection', (client) => { client.on('message', function (msg) { //監聽到信息處理 client.send('服務器收到了信息:' + msg); }); client.on("disconnect", function () { //斷開處理 console.log("client has disconnected"); }); }); console.log("listen 1234...");
客戶端:
$(function () { var ioiosocket = io.connect('http://localhost:1234/'); var $ul = $("ul"); var $input = $("input"); iosocket.on('connect', function () { //接通處理 $ul.append($('<li>連上啦</li>')); iosocket.on('message', function (message) { //收到信息處理 $ul.append($('<li></li>').text(message)); }); iosocket.on('disconnect', function () { //斷開處理 $ul.append('<li>Disconnected</li>'); }); }); $input.keypress(function (event) { if (event.which == 13) { //回車 event.preventDefault(); console.log("send : " + $input.val()); iosocket.send($input.val()); $input.val(''); } }); });
Websocket既然能支持跨域方法,那就是說,一個開放給公網的Websocket服務任何人都能訪問,這樣的話會使數據變得很不安全,所以可以通過對連接域名進行認證即可。
服務器反代
學習路程首先了解了一下什么是反代,在計算機網絡中,反向代理是代理服務器的一種。服務器根據客戶端的請求,從其關聯的一組或多組后端服務器(如Web服務器)上獲取資源,然后再將這些資源返回給客戶端,客戶端只會得知反向代理的IP地址,而不知道在代理服務器后面的服務器簇的存在。 -- 節選自百度百科
反向代理服務器:就nginx把http請求轉發到另一個或者一些服務器上。從而輕松實現跨域訪問。比如服務器中分別部署了N個服務器,當客戶端發起請求時不用直接請求服務器中N個節點上的服務,只需要訪問我們的代理服務器就行了,代理服務器根據請求內容分發到不同服務器節點。這僅是一種使用場景,當然還可以做負載均衡等。
反向代理理解起來不是特別的難,平時生活中最常見的例子,當我們撥打人工客服的時候,并不是直接撥打客服的某一個電話號碼,而是撥打總機號碼,當我們撥打然后由總機進行處理,然后再分發給不同的客服人員。r然而當服務人員需要讓你掛斷電話等待回撥的時候,也不是直接撥打到你的電話,同樣是也通過總機之后再轉發到你的電話。其實這個總機也就相當于反代服務器。雖然這個例子不太貼切但是多多少少就是這個意思。
由于不太懂Nginx不知道該如何處理這個部分,只是對反向代理做了一個簡單的了解,等以后學習了Nginx會補上相關代碼。
Nodejs代理跨域
使用Nodejs進行跨域在我看來,就是使用Node服務做了一個中間代理轉發,其原理和反向代理差不多,當訪問某一個URL時需要通過服務器分發到另一個服務器URL地址中。這里就不過多的贅述了,直接看代碼吧。
示例代碼入下:
main.js
import http from "http"; import httpProxy from "http-proxy"; // 新建一個代理 Proxy Server 對象 const proxy = httpProxy.createProxyServer({}); // 捕獲異常 proxy.on('error', function (err, req, res) { res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('error'); }); // 在每次請求中,調用 proxy.web(req, res config) 方法進行請求分發 const server = http.createServer((req, res) => { // 在這里可以自定義你的路由分發 let host = req.headers.host, ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; switch(host){ case 'www.a.com': proxy.web(req, res, { target: 'http://localhost:3000' }); break; case 'www.b.com': proxy.web(req, res, { target: 'http://localhost:4000' }); break; default: res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello Aaron!'); } }); server.listen(8080);
如代碼所示,當訪問www.a.com的時候,請求就被轉發到了3000接口上,訪問www.b.com時就被轉發到了4000這個接口上。這樣就簡單的完成了一個反向代理的工作。
在使用vue開發的時候難免也會遇到跨域問題,或許你根本就沒有遇到,可能你們正好處于同一個域里面,還有一種可能就是,后端同學或者運維同學已經處理好有關跨域的相關操作。但是當在開發過程中遇到跨域的時候,什么前端應該有對應的解決辦法。vue-cli是基于Node服務的,所以我們可以利用這個服務來做代理工作,暫時解決開發中的跨域問題。
build/webpack.config.js
module.exports = { devServer: { historyApiFallback: true, proxy: [{ context: '/login', // url以/login為開頭時啟用代理 target: 'http://www.a.com:8080', // 代理跨域目標接口 changeOrigin: true, secure: false, // 當代理某些https服務報錯時用 cookieDomainRewrite: 'www.b.com' // 可以為false,表示不修改 }], noInfo: true } }
在開發過程中遇到的可以通過這種方式解決,但是到達生產環境時到底使用什么方法還是需要斟酌的,畢竟要使服務數據變得更加的安全才是最好的。
“分析web前端開發中跨域問題”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。