摘要:說明是否允許通訊同一域名允許同一域名下的不同文件夾允許不同端口號不允許不同協議不允許不同域名不允許主域相同,子域不同不允許跨域解決方案由于瀏覽器同源策略是允許標簽這樣的跨域資源嵌套的,所以標簽的資源不受同源策略的限制。
前言
本著學習和總結的態度寫的技術輸出,文中有任何錯誤和問題,請大家指出。更多的技術輸出可以查看我的 github博客。
整理了一些前端的學習資源,希望能夠幫助到有需要的人,地址: 學習資源匯總。
跨域跨域指的是協議(protocol ),域名(host),端口號(post)都不相同的資源之間嘗試著進行交互通信,而由于受瀏覽器同源策略的限制,無法正常進行交互通信。
最常見的實際場景就是在項目開發過程中,會存在請求第三方其他域下的資源,例如:使用地圖 API 的時候,設置密鑰的時候需要設置白名單才能正常使用地圖 API。
使用 AJAX 請求第三方不同域下的數據資源的時候,如果不處理跨域問題,便不能成功發送 HTTP 請求,且瀏覽器會發出錯誤警告。
同源策略MDN 解釋: 同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的重要安全機制。
瀏覽器的同源策略的目的就是為了防止 XSS,CSRF 等惡意攻擊。
同源策略的交互方式有三種:
通常允許跨域寫操作,例如鏈接,重定向等。
通常允許跨域嵌套資源,例如 img,script 標簽等。
通常不允許跨域讀操作。
跨域場景只有資源之間的協議,域名和端口號都相同,才是同一個源。
下面是關于同源以及不同源之間的跨域描述。
URL | 說明 | 是否允許通訊 |
---|---|---|
http://www.demo.com/a.html http://www.demo.com/b.html http://www.demo.com/c.html |
同一域名 | 允許 |
http://www.demo.com/news/a.html http://www.demo.com/center/b.... http://www.demo.com/server/c.... |
同一域名下的不同文件夾 | 允許 |
http://www.demo.com/a.html http://www.demo.com:80/b.html |
不同端口號 | 不允許 |
http://www.demo.com/a.html https://www.demo.com/b.html |
不同協議 | 不允許 |
http://www.demo.com/a.html http://www.test.com/b.html |
不同域名 | 不允許 |
http://www.demo.com/a.html http://test.demo.com/b.html |
主域相同,子域不同 | 不允許 |
由于瀏覽器同源策略是允許 script 標簽這樣的跨域資源嵌套的,所以 script 標簽的資源不受同源策略的限制。
JSONP 的解決方案就是通過 script 標簽進行跨域請求。
前端設置好回調函數,并把回調函數當做請求 url 攜帶的參數。
后端接受到請求之后,返回回調函數名和需要的數據。
后端響應并返回數據后,返回的數據傳入到回調函數中并執行。
也可以使用 AJAX GET 請求方式來跨域請求(axios GET 方式跨域同理)。
優缺點:
兼容性好,低版本的 IE 也支持這種方式。
只能支持 GET 方式的 HTTP 請求。
只支持前后端數據通信這樣的 HTTP 請求,并不能解決不同域下的頁面之間的數據交互通信問題。
2. CORSCORS 跨域資源共享允許在服務端進行相關設置后,可以進行跨域通信。
服務端未設置 CORS 跨域字段,服務端會拒絕請求并提示錯誤警告。
服務端設置 Access-Control-Allow-Origin 字段,值可以是具體的域名或者 "*" 通配符,配置好后就可以允許跨域請求數據。
服務端如何設置跨域字段? 后端語言設置跨域的方式都不一致,具體可參考后端語言本身的 API。
Node 端設置
res.writeHead(200, { "Access-Control-Allow-Origin": "*" }); // 或者使用了 Express 這樣的框架 res.header("Access-Control-Allow-Origin", "*");
關于 CORS 的詳細,可以參考這篇筆記,CORS跨域資源共享。
3. Server Proxy通過服務端代理請求的方式也是解決瀏覽器跨域問題的方案。同源策略只是針對瀏覽器的安全策略,服務端并不受同源策略的限制,也就不存在跨域的問題。具體步驟如下:
前端正常請求服務端提供的接口。比如請求接口:http://localhost:3000 。
通過服務端設置代理發送請求,請求到數據后再將需要的數據返回給前端。比如設置的代理請求接口是 https://cnodejs.org/api/v1/to... ,服務端代理將數據請求回來之后再將數據 http://localhost:3000 接口返回給前端。
// 服務端代理請求代碼 // 服務端只是簡單的通過正常的 HTTP 請求的方式來代理請求接口數據 // 或者也可以使用 proxy 模塊來代理,至于怎么使用 proxy 模塊,待研究完善 var url = "https://cnodejs.org/api/v1/topics"; https.get(url, (resp) => { let data = ""; resp.on("data", chunk => { data += chunk; }); resp.on("end", () => { res.writeHead(200, { "Access-Control-Allow-Origin": "*", "Content-Type": "application/json; charset=utf-8" }); res.end(data); }); })4. location.hash + iframe
location.hash + iframe 跨域通信的實現是這樣的:
不同域的 a 頁面與 b 頁面進行通信,在 a 頁面中通過 iframe 嵌入 b 頁面,并給 iframe 的 src 添加一個 hash 值。
b 頁面接收到了 hash 值后,確定 a 頁面在嘗試著與自己通信,然后通過修改 parent.location.hash 的值,將要通信的數據傳遞給 a 頁面的 hash 值。
但由于在 IE 和 Chrmoe 下不允許子頁面直接修改父頁面的 hash 值,所以需要一個代理頁面,通過與 a 頁面同域的 c 頁面來傳遞數據。
同樣的在 b 頁面中通過 iframe 嵌入 c 頁面,將要傳遞的數據通過 iframe 的 src 鏈接的 hash 值傳遞給 c 頁面,由于 a 頁面與 c 頁面同域,c 頁面可以直接修改 a 頁面的 hash 值或者調用 a 頁面中的全局函數。
大致流程就是:
a 頁面代碼
b 頁面代碼
c 頁面代碼
優缺點:
hash 傳遞的數據容量有限。
數據直接暴露在 url 中。
5. document.domain + iframe該方案只限于主域相同子域不同的資源跨域解決方案。
實際應用場景:
之前的項目開發中,經常碰到這樣的跨域問題,大致類似于在開發新產品的產品頁中,在沒有正式上線之前,一般都是上傳到內部的測試環境中,比如測試環境的域名是 test.admin.com/xxx/xxx,而項目的測試環境的域名是 consumer-test.admin.com/xxx/xxx 這樣的,產品頁是多帶帶分離部署上線,再通過 iframe 嵌套到項目中。在內部測試過程中,由于產品頁測試環境和項目測試環境主域相同而子域不同,且產品頁中需要用到項目中定義的全局公共資源,由于跨域問題,這些公共資源是獲取不到的。
這種場景的跨域解決方案就是利用 document.domain 設置。在產品頁和項目中將 document.domain 設置成相同域就可以實現跨域,嵌套的產品頁就可以訪問父頁面的公共資源了。需要注意的一點就是,document.domain 的設置是有限制的,只能設置成自身或者更高級的父域,且主域必須相同。
項目頁面
產品頁
6. window.name + iframewindow.name 指的是當前瀏覽器窗口的名稱,默認為空字符串,每個窗口的 window.name 都是獨立的。iframe 嵌套的頁面中也有屬于自己的 window 對象,這個 window 是top window 的子窗口,也同樣擁有 window.name 的屬性。
window.name 的獨特之處在于當在頁面設置 window.name 的值,其實就是相當于給這個窗口設置了名稱,而后在這個窗口加載其他頁面(甚至不同域的頁面),window.name 的值依然存在(如果沒有重新設置那么值不會變化),并且 window.name 的值支持比較大的存儲(2MB)。
例如: 隨便找個頁面打開控制臺,給當前窗口設置名稱。
window.name = "test-name";
設置好之后可以在這個窗口下跳轉到其他頁面
window.location = "https://www.baidu.com";
頁面跳轉到了百度首頁,但是 window.name 的值依然是之前設置的值,因為是在一個窗口中跳轉的頁面,窗口名稱并不會被修改。
具體的跨域解決方式如下。
http://localhost:8080/a.html 與 http://localhost:8081/b.html 跨域通信,a 頁面通過 iframe 嵌套 b 頁面,b 頁面中設置好 window.name 的值,由于是不同域,a 頁面不能直接訪問到 b 頁面設置的 window.name 的值,需要一個與 a 頁面同域的中間頁來代理作為 a 頁面與 b 頁面通信的橋梁。
a.html
b.html
中間代理頁,只需要跟 a 頁面保持同域就可以了,例如: http://localhost:8080/c.html 。
7. window.postMessagepostMessage 是 HTML5 的新特性,用于頁面之間跨域通信。
postMessage 方法接受兩個必要的參數:
message: 需要傳遞的數據。
targetOrigin: 數據傳遞的目標窗口域名,值可以是具體的域名或者 "*" 通配符。
a.html
b.html
總結協議,域名,端口號不相同的資源之間相互通信,就會產生跨域問題。
處于安全考慮,瀏覽器的同源策略限制了不同域之間相互通信。
JSONP,CORS,Server Proxy 跨域解決方式的應用場景都是用于前后端之間的數據通信,其他跨域解決方案主要是解決窗口頁面之間的數據通信。
JSONP 只支持 GET 方式的 HTTP 請求。
CORS 跨域資源請求需要后端支持。
Server Proxy 直接讓后端代理發送請求。
后記所有的跨域解決方案都有對應的 DEMO 實例,可在 DEMO 中查看。想要看運行效果,可以全局安裝 http-server 模塊。
npm install -g http-server
本著學習和總結的態度寫的技術輸出,文中有任何錯誤和問題,請大家指出。更多的技術輸出可以查看我的 github博客。
整理了一些前端的學習資源,希望能夠幫助到有需要的人,地址: 學習資源匯總。
參考https://zhuanlan.zhihu.com/p/...
https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://juejin.im/post/5815f4...
https://juejin.im/post/59c132...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98076.html
摘要:上節我們講了同源策略,這節我們講講如何跨域。當這些從的腳本執行出錯,因為違背了同源策略為了保證用戶信息不被泄露,錯誤信息不會顯示出來,取而代之只會返回一個。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思想,我們開課啦(每...
摘要:關于,強烈推薦閱讀跨域資源共享詳解阮一峰另外,這里也整理了一個實現原理圖簡化版如何判斷是否是簡單請求瀏覽器將請求分成兩類簡單請求和非簡單請求。 前言 從剛接觸前端開發起,跨域這個詞就一直以很高的頻率在身邊重復出現,一直到現在,已經調試過N個跨域相關的問題了,16年時也整理過一篇相關文章,但是感覺還是差了點什么,于是現在重新梳理了一下。 個人見識有限,如有差錯,請多多見諒,歡迎提出iss...
摘要:在接觸前端開發起,跨域這個詞就一直以很高的頻率在我們學習工作中重復出現,最近在工作中遇到了跨域的相關問題,這里我把它總結記錄一下。 在接觸前端開發起,跨域這個詞就一直以很高的頻率在我們學習工作中重復出現,最近在工作中遇到了跨域的相關問題,這里我把它總結記錄一下。關于跨域,有N種類型,現在我只專注于ajax請求跨域(ajax跨域只是屬于瀏覽器同源策略中的一部分,其它的這里不做介紹),內容...
閱讀 2469·2021-11-15 11:38
閱讀 2844·2021-11-02 14:44
閱讀 3821·2021-09-26 10:13
閱讀 3060·2021-08-13 15:02
閱讀 780·2019-08-30 15:56
閱讀 1450·2019-08-30 15:53
閱讀 2363·2019-08-30 13:01
閱讀 3193·2019-08-29 12:57