跨域問題詳解

淺談跨域

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

1.跨域是什麼?

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

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.

咱們把它丟到百度翻譯能夠的到以下解釋:html

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

咱們把它理順一下能夠變成:node

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

咱們能夠在簡化一下這個信息:網頁間的XMLHttpRequest請求被CORS策略給阻止了。好的,來到這裏咱們已經知道了跨域請求失敗的緣由是什麼了。CORS策略阻止了它!!ajax

CORS是什麼?

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

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與代理服務器相關內容,我過兩天整理後再更新,累了

相關文章
相關標籤/搜索