前端跨域問題原因分析以及解決方式

前端跨域問題的解決方案

1. 造成跨域的原因

跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源.這裏的跨域是廣義的.
廣義的跨域包括:

  • 資源跳轉: 鏈接,重定向,表單提交
  • 資源嵌入: <link>,<script>,<img>,<iframe>等 DOM 標籤
  • 腳本請求: javascript 發起的 Ajax 請求等

而我們常說的跨域是狹義的,是由瀏覽器同源策略引起的一類請求場景.

The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin. It helps isolate potentially malicious documents, reducing possible attack vectors.

來自 MDN

如果兩個域名的協議,域名,端口都相同,那我們就說這兩個域名是同源的.

2. 同源策略限制些什麼?

  1. 不能向工作在不同源的服務請求數據,即不能發送 Ajax 請求;
  2. 無法獲取不同源的 document / cookies 等 BOM 和 DOM,可以說任何有關另一個源的信息都無法得到.

3. 爲什麼會有同源策略

3.1 爲什麼要限制不同源發送請求

假設兩個頁面,a 頁面和 b 頁面.如果沒有任何限制,b 頁面可以向 a 頁面請求任何信息,那如果 a 頁面是個
銀行之類的頁面,那就可以進行轉賬之類的請求.
那既然如此,爲什麼不限制寫,只限制讀?
因爲如果連請求都發送不出去,那就不能做跨域資源共享了.

3.2 爲什麼限制跨域的 DOM 讀取?

如果不加以限制,很容易通過 iframe 僞裝其網站.進而可以獲取用戶的登錄信息等.

4. 跨域的解決方式

4.1 CORS

服務器設置:

ACCESS-CONTROL-ALLOW-ORIGIN: *

只要瀏覽器檢測到響應頭帶上了 CORS,並且允許的源包括了本網站,那麼就不會攔截請求響應。

CORS 分爲"簡單請求"以及"預檢請求":

  1. 簡單請求
    使用下列方法之一:

    • GET
    • POST
    • HEAD

    以及滿足 Fetch 規範定義了對 CORS 安全的首部字段集合,不得人爲設置該集合之外的其他首部字段。
    而且 Content-Type 的值僅爲下列三者之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  2. 預檢請求
    與上述簡單請求不一樣."需預檢的請求"要求必須首先使用 OPTIONS 方法發起一個預檢請求到服務器,
    以獲知服務器是否允許該實際請求。"預檢請求"的使用,可以避免跨域請求對服務器的用戶數據產生未預期的影響。
    當滿足以下任一條件時,即應首先發送預檢請求:

    • 非簡單請求的方法
    • 人爲設置了對 CORS 安全的首部字段集合之外的其他首部字段。
    • 非簡單請求的 Content-Type
    • 請求中的XMLHttpRequestUpload 對象註冊了任意多個事件監聽器。
    • 請求中使用了ReadableStream對象。

另外,還有附帶身份驗證的請求,也就是攜帶 cookies.
這個需要前端在請求實例中設置:

// 將 XMLHttpRequest 的 withCredentials 標誌設置爲 true
const xml = new XMLHttpRequest();
// ...
xml.withCredentials = true;

這時,後端需要作出相應的設置.

來自MDN

4.2 JSONP

JSONP 能夠跨域的原理就是:動態創建 script 標籤,利用 script 標籤的 src 請求沒有跨域的限制.

代碼示例

function updateList (data) {
    console.log(data);
}
let tag = document.createElement("script")
tag.src = "http://otherdomain.com/request?callback=updateList";
document.head.appendChild(tag);

代碼定義一個全局函數,然後把這個函數名添加到 script 標籤中 src 屬性的參數 callback 中,
script 的 src 就是需要跨域的請求.服務端收到請求之後,將數據放入 callback 屬性的屬性值中:
updateList("somedata"),然後返回給客戶端:

// script 響應返回的js內容爲
updateList([{
    name: 'hello'
}]);

也就是客戶端執行 傳遞的方法 updateList ,函數的參數即是本次跨域請求返回的數據.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章