前端中的同源策略與三種跨域資源共享方法

同源策略

什麼是同源

在瞭解跨域這個概念以前首先要知道的是何爲同源策略。所謂的同源是一種安全機制,爲了預防某些惡意行爲(例如 Cookie 竊取等),瀏覽器限制了從同一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。而知足同源要具有三方面:協議相同域名相同端口相同javascript

如下是對於http://domain.com/dir/index.html(默認端口 80)來進行同源判斷:html

  1. http://domain.com/dir2/info.html(同源)
  2. https://domain.com/dir/index.html(非同源,協議不相同)
  3. http://www.domain.com/dir/index.html(非同源,域名不一樣)
  4. http://domain.com:233/dir/index.html(非同源,端口不一樣)

什麼地方有要求同源

  1. Ajax 通訊
  2. Cookie
  3. LocalStorage
  4. IndexDB
  5. DOM 的操做

跨域資源共享

同源策略對於用戶信息安全是必不可少的,可是實現合理的跨域請求也是很重要的,因而 W3C 就定了一個叫CORS(Cross-Origin Resource Sharing)的草案,也就是跨域資源共享。其基本思想就是使用自定義的 HTTP 頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功或是失敗。java

CORS 的簡單請求原理

實現 CORS 須要瀏覽器與服務器的同時支持。例如發送一個簡單的GETPOST請求,瀏覽器會爲其添加一個Origin的頭,其包含頁面的源信息(協議、域名和端口),如:jquery

Origin: http://domain.com
複製代碼

若服務器認爲該請求可接受,就在Access-Control-Allow-Origin頭部中回發相同的源信息(咱們有時調用的公共 API,大部分都是將該頭部設爲*,可是它們都不發送 Cookie)。要注意的是請求和響應都不包含 Cookie 信息。nginx

以上都爲簡單請求,對於非簡單請求,CORS 經過一種叫作 Preflighted Requests 的透明服務器驗證機制支持開發者使用自定義頭部信息或者 GET 和 POST 以外的方法,不過代價是在正式通訊前增長一次 HTTP 請求,這裏就不詳細描述了。ajax

瀏覽器對 CORS 的實現

現代瀏覽器都對 CORS 提供了原生支持(IE八、9 是利用XDomainRequest,不過已廢棄),無需編寫額外代碼便可觸發簡單的跨域行爲,由於瀏覽器會自動幫你添加一些頭部信息,可是有如下限制:json

  1. 不可以使用setRequestHeader()設置自定義頭部。
  2. 默認狀況下不能請求 Cookie 等憑據,除非服務器在響應頭中將Access-Control-Allow-Credentials設爲true
  3. 調用getAllResponseHeaders()會返回空字符串。

圖像 Ping

該跨域技術主要是利用<img>標籤設置src屬性(請求地址一般都帶有查詢字符串),而後監聽該<img>onloadonerror事件來判斷請求是否成功。響應的內容一般是一張 1 像素的圖片或者204響應。跨域

圖片 Ping 有兩個缺點:瀏覽器

  1. 由於是經過<img>標籤實現,因此只支持GET請求。
  2. 沒法訪問服務器響應腳本,只能用於在瀏覽器與服務器之間進行單向通行。

因爲以上特色,圖片 Ping 方法經常使用於跟蹤用戶點擊頁面或動態廣告的曝光次數。安全

JSONP

JSONP 是 JSON with padding 的簡寫,其主要是利用動態建立<script>標籤向服務器發送 GET 請求,服務器收到請求後將數據放在一個指定名字的回調函數中並傳送回來。接下來看一下簡單示例: 瀏覽器

//對建立標籤行爲進行封裝
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://domain.com/data?callback=getdata')
}

//服務器收到上面的請求後,將數據放在回調函數的參數(data)中返回
function getdata(data) {
  console.log(data)
}
複製代碼

jQuery 也有對 JSONP 的封裝,有興趣的能夠了解一下(文章尾部連接)

服務器

//服務器獲取參數名後,將回調函數和參數拼接爲字符串返回
response.send(
  `${query.callback}({ "name": "Hello" })`
)
複製代碼

其餘的跨域方法

跨域方法其實還有很多,這裏先總結這麼多,日後若時間容許的話就更新 😬

  • HTML5 的 postMessage
  • WebSocket(固然協議就不同了)
  • document.domain(iframe)
  • location.hash(iframe)
  • window.name
  • nginx 反向代理

相關參考

相關文章
相關標籤/搜索