跨域問題詳解


淺談跨域

閱讀須知: 作者是一個在校大學生,尚未工作,以下內容依據個人理解與網上資料編寫。若有錯誤,還請指出,感激不盡。網上對於跨域的解釋大多是一堆文字,對於初學者來說往往較難理解,這篇博客我將利用NodeJs搭建一個簡易的服務器用於模擬跨域,不懂NodeJs的小伙伴也不用緊張,只是借助於NodeJs來快速搭建一個http服務器。我將以最簡單的代碼去還原跨域問題。若有興趣的小伙伴,可自行百度學習(菜鳥教程)。本篇博文所有代碼均已跑通且會上傳至個人倉庫。歡迎各位指正錯誤。

1.跨域是什么?

跨域.PNG
這就是一個跨域引起的錯誤。或許許多小伙伴,一遇到錯誤就直接百度尋找答案,但有時候我們不妨看看錯誤信息,這對我們理解問題可能會有不錯的幫助,而不是遇到問題就百度,goole。我們來看看錯誤信息都告訴我們什么?

Access to XMLHttpRequest at 'http://127.0.0.1:8002/index.html' from origin 'http://127.0.0.1:8001' has been blocked by CORS policy: No'Access-Control-Allow-Origin' header is present on the requested resource.

我們把它丟到百度翻譯可以的到如下解釋:

CORS策略已阻止從“http://127.0.0.1:8002/index.html”源“http://127.0.0.1:8001”對XMLHttpRequest的訪問:請求的資源上不存在“Access-Control-Allow-origin”頭。

我們把它理順一下可以變成:

一個網頁請求另外一個網頁的資源被CORS策略給阻止了,原因XMLHttpRequest的請求不存在“Access-Control-Alloworigin"頭,如果你恰巧有網絡協議方面的知識儲備,或許你已經了解跨域是什么了,以及如何解決。

我們可以在簡化一下這個信息:網頁間的XMLHttpRequest請求被CORS策略給阻止了。好的,來到這里我們已經知道了跨域請求失敗的原因是什么了。CORS策略阻止了它!!

CORS是什么?

(推薦閱讀MDN的文章:中文版:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS ,英文版:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)

CORS:Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own.

由上邊的介紹可知:CORS是不同域之間資源共享的一種機制,它使用額外的Http頭來告訴瀏覽器讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。

跨域的安全限制,主要是針對瀏覽器端來說的,服務器端是不存在跨域安全限制的。。所以我們可以通過代理服務器去解決跨域問題。

域:簡單理解由協議+域名+端口組成

譬如文章開頭圖片中的兩個域http://127.0.0.1:8002/index.html與http://127.0.0.1:8001是由於端口號不同而造成了跨域。http是他們的協議,127.0.0.1是他們的Ip地址,這里是本機Ip。8001,8002是他們的端口號,簡單點說ip地址是你的電腦在網絡世界里的標識。(Ip不是唯一不變的,它隨着你接入的網絡可能會發生改變,每台電腦的網卡還有一個物理地址MAC地址。MAC地址用於在網絡中唯一標示一個網卡,一台設備若有一或多個網卡,則每個網卡都需要並會有一個唯一的MAC地址,這里不過多贅述,以后或許會更新相關內容的博文)

2.跨域的原因是什么

雖然在上邊的翻譯中告訴我們是因為CORS策略給阻止了請求,但我們通過查閱CORS在MDN上的解釋可以知道,CORS是不同域之間共享資源的一種機制,也就是說它可以說是解決跨域的一種方案。那么引起跨域的原因是什么?

上面說到跨域只存在於瀏覽器之間,這是因為瀏覽器存在有一個同源策略。什么是同源策略(SOP)呢?可以看一看MDN上的文章(https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy)。

同源策略是瀏覽器的一個安全功能,不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方資源。所以xyz.com下的js腳本采用ajax讀取abc.com里面的文件數據是會被拒絕的。同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。

阮一峰的博客中有一段跨域同源策略的描述

同源政策的目的:是為了保證用戶信息的安全,防止惡意的網站竊取數據。
設想這樣一種情況:A網站是一家銀行,用戶登錄以后,又去瀏覽其他網站。如果其他網站可以讀取A網站的Cookie,會發生什么?很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會泄漏。更可怕的是,Cookie 往往用來保存用戶的登錄狀態,如果用戶沒有退出登錄,其他網站就可以冒充用戶,為所欲為。因為瀏覽器同時還規定,提交表單不受同源政策的限制。由此可見,"同源政策"是必需的,否則Cookie 可以共享,互聯網就毫無安全可言了。

在這里簡單介紹一下cookie,因為理解了cookie能更好的理解瀏覽器與服務器間的交互。我們知道瀏覽器與服務器間使用過http協議來進行交互的,但是HTTP協議是無狀態的,服務器是無法通過接收到的HTTP請求來區分是哪個用戶發起的請求,即服務器不知道用戶上一次做了什么,這嚴重阻礙了交互式Web應用程序的實現。在典型的網上購物場景中,用戶瀏覽了幾個頁面,買了一盒餅干和兩飲料。最后結帳時,由於HTTP的無狀態性,不通過額外的手段,服務器並不知道用戶到底買了什么。為了做到這點,就需要使用到Cookie了。服務器可以設置或讀取Cookies中包含信息,借此維護用戶跟服務器會話中的狀態。

如何查看Cookie?

可以打開菜鳥教程里有關cookie的介紹https://www.runoob.com/js/js-cookies.html

Cookie.PNG

各位可以發現Cookies是有分組的,每個域下邊存在有不同的cookie值,Cookie是由服務端生成的,發送給客戶端(通常是瀏覽器)的。Cookie總是保存在瀏覽器中。

img

當瀏覽器與服務器之間通信時,瀏覽器會在每個http請求中攜帶當前域下的cookie。

到這里我們已經大概了解什么是同源策略,為什么要有同源策略。

同源策略限制的行為:

(1) 無法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB。

(2) 無法接觸非同源網頁的 DOM。

(3) 無法向非同源地址發送AJAX請求(可以發送,但瀏覽器會拒絕接受響應)。

不受同源策略限制的情況:

有一些情況是不受同源策略的影響,簡單列舉如下:

(1)頁面中的超鏈接,點擊可以訪問其他不同源的頁面。

(2)表單提交,不同源的頁面可以相互提交表單數據。

(3)通過Html標簽請求資源,如scrpit,img標簽。

3.解決跨域

這里介紹三中種跨域的解決方案 JSONP,代理服務器和CORS

JSONP

JSONP利用的是通過HTML標簽請求資源,不受同源策略影響。它的基本思想是,網頁通過添加一個script元素,向服務器請求數據,這種做法不受同源策略限制;服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。 先貼上一段網上摘抄的代碼
# 預先定義好處理數據的回調
function CallbackName(data) {
  console.log('Your public IP address is: ' + data.ip);
};
# 創建scrpit元素請求資源,以備后用
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}
# 在頁面加載完成時調用函數發送指定目標請求
window.onload = function () {
  addScriptTag('http://example.com/ip?callback=CallbackName');
}

初次看這代碼時不太理解,因為當時沒有接觸后端開發,無法理解它們的交互過程。我們要明白一點script標簽請求回來的數據瀏覽器是當成JS去解析的,我們可以簡單驗證一下,雖然沒有資料講述這一部分的內容。

1.PNG
script1.js代碼如下

<h1>11111</h1>

script2.js代碼如下

alert(1);

當把這個頁面打開,會發現頁面彈出兩次彈框,控制台提示無法解析h1標簽的錯誤。所以可以大概理解瀏覽器是將請求回來的數據當成js代碼執行。

這時候我們就可以通過URL所帶的queryString傳遞我們的函數名,例如下邊這個URL傳遞了CallbackName作為回調函數的名稱,而原先的JS代碼又預先定義了回調函數。當后代給我們返回,Callbackname({dataObj})這樣的字符串時,瀏覽器就會自動調用預先定義的回調函數,而需要的數據就通過{dataObj}傳遞過來了,於是實現了跨域請求。還是不太理解的小伙伴可以去我的倉庫里查看相關代碼。

http://example.com/ip?callback=CallbackName

JSONP只能支持get請求,並且前后端需要商量好回調函數的名稱。

CORS與代理服務器相關內容,我過兩天整理后再更新,累了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM