解決跨域問題

什麼是同源策略javascript

同源策略是瀏覽器的一項最爲基本同時也是必須遵照的安全策略。同源策略的存在,限制了「源」自A的腳本只能操做「同源」頁面的DOM,「跨源」操做來源於B的頁面將會被拒絕。所謂的「同源」,必需要求相應的URI在以下3個方面均是相同的。java

  1. 主機名稱(域名/子域名或者IP地址)
  2. 端口號
  3. 網絡協議(Scheme,分別採用「http」和「https」協議的兩個URI被視爲不一樣源

對於一段JavaScript腳原本說,其「源」與它存儲的地址無關,而取決於腳本被加載的頁面。好比在某個頁面中經過<script>標籤引用了來源於不一樣地方的兩個JavaScript腳本,它們均與當前頁面同源。ajax

<script src="http://www.a.com/scripts/a.js"></script>
<script src="http://www.b.me/scripts/b.js"></script>

除了<script>標籤其它一些具備src屬性的標籤(好比<img>),它們均具備跨域加載資源的能力,因此同源策略對它們不作限制。編程

同源策略主要限制了經過XMLHttpRequest實現的Ajax請求,若是請求的是一個「異源」地址,瀏覽器將不容許讀取返回的內容。json

JSONP實現跨域資源共享api

經過<script>標籤的src屬性加載的JavaScript腳本跨域

<script type="text/javascript" src="http://localhost:8080/api/test?callback=test"></script>

<script type="text/javascript">
function test(arg){

}
</script>

JSONP是利用<script>的src標籤加載的腳本不受同源策略約束而採起的一種編程技巧,不是一種官方協議。因爲具備src屬性的HTML標籤均經過HTTP-GET的方式來加載目標資源,JSONP只適用於HTTP-GET請求。瀏覽器

咱們能夠利用JQuery發送JSONP的Ajax跨域請求,調用$.ajax方法並將dataType參數設置爲「jsonp」緩存

<script type="text/javascript">
    $(function ()
    {
        $.ajax({
             dataType : "jsonp"
        });
    });
</script>

CORS(Cross-Origin Resource Sharing)安全

基於Web的資源共享涉及到兩個基本的角色,即資源的提供者和消費者。即顯示在瀏覽器中的某個Web頁面經過調用Web API的方式來獲取它所需的資源,資源提供者爲Web API自己,經過發送Ajax請求來調用Web API的JavaScript程序爲資源的消費者。

CORS旨在定義一種規範讓瀏覽器在接收到從提供者獲取的資源時可以正決定是否應該將此資源分發給消費者做進一步處理。CROS利用資源提供者的顯式受權來決定目標資源是否應該與消費者共享。瀏覽器須要獲得提供者的受權以後纔會將其提供的資源分發給消費者。

若是瀏覽器 自身提供對CROS的支持,由它發送的請求會攜帶一個名爲「Origin」的報頭代表請求頁面所在的站點。

資源獲取請求被提供者接收以後,它能夠根據該報頭肯定提供的資源須要共享給誰。資源提供者的受權經過一個名爲「Access-Control-Allow-Origin」的響應報頭來承載,其報頭值表示獲得受權的站點。通常來講,若是資源的提供者承認了當前請求的「Origin」報頭攜帶的站點,那麼它會將該站點做爲「Access-Control-Allow-Origin」響應報頭的值。

當瀏覽器接收到包含資源的響應以後,會提取此「Access-Control-Allow-Origin」響應報頭的值。若是此值爲「*」或者包含的源列表包含此前請求的源(即請求的「Origin」報頭值),意味着資源的消費者獲取了提供者獲取和操做資源的權限,因此瀏覽器會容許JavaScript程序操做獲取的資源。若是此響應報頭不存在或者其值爲「null」,客戶端JavaScript程序針對資源的操做會被拒絕。

簡單(HTTP)方法(Simple Method)」、「簡單(請求)報頭(Simple Header)」和「自定義請求報頭(Author Request Header/Custom Request Header)」

CORS規範將GET、HEAD和POST這三個HTTP方法視爲「簡單HTTP方法」,而將請求報頭Accept, Accept-Language, Content-Language以及採用以下三種媒體類型的報頭Content-Type稱爲「簡單請求報頭」

  1. application/x-www-form-urlencoded
  2. multipart/form-data
  3. text/plain

由JavaScript程序自行添加的報頭(好比調用XMLHttpRequest的setRequestHeader方法能夠爲生成的Ajax請求添加任意報頭),被稱爲「自定義報頭」。

簡單請求/非簡單跨域資源請求

CORS規範將服務以下條件的跨域資源請求劃分爲簡單請求:請求採用簡單HTTP方法,而且其自定義請求報頭空或者全部自定義請求報頭均爲簡單請求報頭。

對於簡單跨域資源請求來講,瀏覽器將兩個步驟(取得受權和獲取資源)合二爲一。若是針對請求的處理過程會涉及到對資源的改變,這樣作就會有問題了。按照CORS規範的規定,瀏覽器應該採用一種被稱爲「預檢」的機制來完成非簡單跨域資源請求。

所謂預檢機制就是說瀏覽器在發送真正的跨域資源請求前,先發送一個預檢請求。預檢請求爲一個採用HTTP-OPTIONS方法的請求,這是一個不包含主體的請求,同時用戶憑證相關的報頭也會被剔除。基於真正資源請求的一些輔助受權的信息會包含在此預檢請求的相應報頭中。除了表明請求頁面所在站點的「Origin」報頭以外,以下所示的是兩個典型的請求報頭。

  1. Access-Control-Request-Method:真正跨域資源請求採用的HTTP方法。
  2. Access-Control-Request-Headers:真正跨域資源請求攜帶的自定義報頭列表。

資源的提供者在接收到預檢請求以後,根據其提供的相關報頭進行受權檢驗,具體的檢驗邏輯即包括肯定請求站點是否值得信任,以及請求採用HTTP方法和自定義報頭是否被容許。若是預檢請求沒有經過受權檢驗,資源提供者通常會返回一個狀態爲「400, Bad Reuqest」的響應。反之則會返回一個狀態爲「200, OK」的響應,受權相關信息會包含在響應報頭中。除了上面介紹的「Access-Control-Allow-Origin」報頭以外,預檢請求的響應還具備以下3個典型的報頭。

  1. Access-Control-Allow-Methods:跨域資源請求容許採用的HTTP方法列表。
  2. Access-Control-Allow-Headers:跨域資源請求容許攜帶的自定義報頭列表。
  3. Access-Control-Max-Age:瀏覽器能夠將響應結果進行緩存的時間。

瀏覽器在接收到預檢響應以後,會根據響應報頭肯定後續發送的真正跨域資源請求是否會被接受,相關的檢驗包括針對服務端容許站點以及HTTP方法和自定義請求報頭(利用響應報頭「Access-Control-Allow-Methods」和「Access-Control-Allow-Headers」)的檢驗。具體的檢驗邏輯以下

  1. 經過請求的「Origin」報頭表示的源站點必須存在於「Access-Control-Allow-Origin」響應報頭標識的站點列表中。
  2. 響應報頭「Access-Control-Allow-Methods」不存在,或者預檢請求的「Access-Control-Request-Method」報頭表示的請求方法在其列表以內。
  3. 預檢請求的「Access-Control-Request-Headers」報頭存儲的報頭名稱均在響應報頭「Access-Control-Allow-Headers」表示的報頭列表以內。

只有在肯定服務端必定會接受的狀況下,瀏覽器纔會發送真正跨域資源請求。預檢響應結果會被瀏覽器緩存,在「Access-Control-Max-Age」報頭設定的時間內,緩存的結果將被瀏覽器用戶進行受權檢驗,因此在此期間不會再有預檢請求發送。

用戶憑證

在默認狀況下,利用XMLHttpReuqest發送的Ajax請求不會攜帶用戶憑證相關的敏感信息,這裏的用戶憑證類型包括Cookie、HTTP-Authentication報頭以及客戶端X.509證書(採用支持客戶端證書的TLS/SSL)等。若是須要用戶憑證附加到Ajax請求上,須要將XMLHttpReuqest的withCredentials 屬性設置爲True。

W3C的CORS規範,服務端利用響應報頭「Access-Control-Allow-Credentials」來代表自身是否支持用戶憑證。

JavaScript程序利用一個withCredentials屬性爲true的XMLHttpReuqest發送了一個跨域資源請求,可是瀏覽器獲得的響應中不具備一個值爲「true」的響應報頭「Access-Control-Allow-Credentials」,它對獲取資源的操做將會瀏覽器拒絕。

ps:本文參考摘要《ASP.NET Web API 2框架揭祕》一書

相關文章
相關標籤/搜索