JavaScript-CORS 跨域

JavaScript 的同源策略及其"CORS"跨域方案


文章大綱

同源策略

同源是什麼?

在web瀏覽器中,同源策略 限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。javascript

若是兩個頁面的html

  • 1.協議
  • 2.端口(若是有指定)
  • 3.域名

三者都相同,則兩個頁面具備相同的源。前端


舉例說明 http://store.example.com/dir/page.html 同源檢測的示例:java

URL 結果 緣由
http://store.example.com/index.html 成功
http://store.example.com/dir/another.html 成功
https://store.example.com/index.html 失敗 不一樣協議 ( https和http )
http://store.example.com:81/index.html 失敗 不一樣端口 ( 81和80)
http://news.example.com/index.html 失敗 不一樣域名 ( news和store )
http://example.com/index.html 失敗 不一樣域名 (store是一個單獨的自域)

如何跨源,以及場景應用

如下爲4種能夠遇到的跨源node

源的更改

頁面可能會因某些限制而改變他的源。ios

設置 document.domain 的值,爲其當前域或其當前域的父域。nginx

場景 http://store.example.com/dir/page.html 文檔中的一個腳本執行如下語句 document.domain = "company.com" 便可經過同源檢測web

跨源網絡訪問

同源策略控制了不一樣源之間的交互。ajax

使用 CORS 容許跨源訪問。express

場景 由瀏覽器發起的跨域 HTTP 請求 (這個你們接觸的最多)

跨源腳本API訪問

Javascript的APIs中,容許文檔間直接相互引用。可是當兩個文檔的源不一樣時,一些引用方式將對 API對象的訪問添加限制

可使用window.postMessage

場景 使用 <iframe> 嵌套的時候,父子頁面的通訊

跨源數據存儲訪問

存儲在瀏覽器中的數據,如localStorage和IndexedDB,以源進行分割。每一個源都擁有本身單獨的存儲空間,一個源中的Javascript腳本不能對屬於其它源的數據進行讀寫操做

場景 null

瞭解CORS

CORS是什麼?

MDN的網站給出了這樣的2種解釋:

CORS (Cross-Origin Resource Sharing,跨域資源共享)是一個系統,它由一系列傳輸的HTTP頭組成,這些HTTP頭決定瀏覽器是否阻止前端 JavaScript 代碼獲取跨域請求的響應。 CORS 給了web服務器這樣的權限,即服務器能夠選擇,容許跨域請求訪問到它們的資源。

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

實際上着兩種解釋都同樣。我給出這樣的理解:CORS賦予服務端(一般所說的後端)一個能力,本身控制哪些瀏覽器的請求能夠訪問到它的資源,來解決跨域問題。

附:全部的 CORS

HTTP頭 功能
Access-Control-Allow-Origin 指示請求的資源能共享給哪些域。
Access-Control-Allow-Credentials 指示當請求的憑證標記爲 true 時,是否響應該請求。
Access-Control-Allow-Headers 用在對預請求的響應中,指示實際的請求中可使用哪些 HTTP 頭。
Access-Control-Allow-Methods 指定對預請求的響應中,哪些 HTTP 方法容許訪問請求的資源。
Access-Control-Expose-Headers 指示哪些 HTTP 頭的名稱能在響應中列出。
Access-Control-Max-Age 指示預請求的結果能被緩存多久。
Access-Control-Request-Headers 用於發起一個預請求,告知服務器正式請求會使用那些 HTTP 頭。
Access-Control-Request-Method 用於發起一個預請求,告知服務器正式請求會使用哪種 HTTP 請求方法。
Origin 指示獲取資源的請求是從什麼域發起的。

CORS功能概述

功能概述 TL;DR

規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法(特別是 GET 之外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否容許該跨域請求。服務器確認容許以後,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也能夠通知客戶端,是否須要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。

一句話概述:非簡單請求時,會先發送預檢請求,容許後再發送實際請求

附:node-express框架下,服務端的跨域設置

app.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Methods', '*');
  next();
});
複製代碼

CORS關於Cookie

CORS請求默認不發送Cookie和HTTP認證信息,若是想要知道用cookie就要注意3點

  1. Client端 new XMLHttpRequest()withCredentials 設置爲 true
  2. Serive端 HTTP頭 Access-Control-Allow-Credentials 設置爲 true
  3. Serive端 HTTP頭 Access-Control-Allow-Origin 不能設爲星號,必須指定明確的、與請求網頁一致的域名

因此上面的例子要想發送cookie

// service端
`res.header('Access-Control-Allow-Credentials', true);`
`res.header('Access-Control-Allow-Origin', '具體的域名');`
// client端
Jquery `ajax()` `xhrFields: {withCredentials: true}`
Axios `axios.defaults.withCredentials = true`
複製代碼

CORS的簡單請求

上面講了簡單請求,但那些纔是簡單請求呢?咱們稱:若不會觸發 CORS 的預檢請求,稱這樣的請求爲「簡單請求」

如下爲簡單請求:

  1. HTTP Method 組成只能是如下幾種
  • GET
  • POST
  • HEAD
  1. HTTP Headers 組成
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type 只包含如下類型 (form表單請求)
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

注:只有同時知足以上兩個條件時,纔是簡單請求,不然爲非簡單請求

CORS預檢請求又是什麼?

前面說了這麼多預檢請求,咱們來說一講什麼是預檢請求: 若是咱們在client端發送請求時,例如:

// 原生
var invocation = new XMLHttpRequest();

invocation.setRequestHeader('X-EXAMPLE', 'xixihaha');
invocation.setRequestHeader('Content-Type', 'application/xml');

// axios
axios.defaults.headers['X-EXAMPLE'] = 'xixihaha';
axios.defaults.headers['Content-Type'] = 'application/xml';

複製代碼

POST 請求發送一個 XML 文檔,該請求包含了一個自定義的請求首部字段(X-EXAMPLE: xixihaha)。另外,該請求的 Content-Type 爲 application/xml。所以,該請求須要首先發起「預檢請求」。

server端 的HTTP頭設置

Access-Control-Allow-Origin: '具體的域名'
Access-Control-Allow-Methods: POST, GET, OPTIONS // 可包含的參數
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type // 容許的首部字段
Access-Control-Max-Age: 86400
複製代碼

非簡單請求和簡單請求無異,若是瀏覽器的預檢請求被服務器接受,則發送實際請求,未被接受則拒絕請求。

其餘

跨域不止於此

JSONP 動態建立script標籤,而後利用script的src 不受同源策略約束來跨域獲取數據

function addScriptTag() {
    var script = document.createElement("script");
    script.src = "http://foo.example?callback=handleResponse";
    document.body.appendChild(script);
}

function handleResponse() {
  console.log('跨域數據');
};
複製代碼

如下跨域方案不作過多解釋

上文提到的 postMessage()

nginx轉發,即架設服務器代理

window.name

參考

阮一峯的網絡日誌

MDN web docs CORS

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息