關於CORS跨域問題的理解

原由

由於這段時間一個項目先後端分別部署在不一樣服務器的須要,抽空學習了一下CORS問題,不足之處,歡迎指教.php

 

什麼是CORShtml

CORS是一個w3c標準,全稱是"跨域資源共享"(Cross-origin resource sharing),但一個請求url的協議,域名,端口三者之間任意與當前頁面地址不一樣即爲跨域.它容許閱覽器向跨源服務器發送XMLHttpRequest請求,從而客服AJAX只能同源使用的限制.web

 

CORS簡介apache

瀏覽器默認的安全限制爲同源策略,即JavaScript或Cookie只能訪問同源(相同協議,相同域名,相同端口)下的內容。但因爲跨域訪問資源須要,出現了CORS機制,這種機制讓web服務器能跨站訪問控制,使跨站數據傳輸更安全。CORS須要閱覽器和服務器同時支持,目前,主流的閱覽器都支持cors。後端

 

CORS的兩種請求方式跨域

瀏覽器將CORS請求分爲兩類:簡單請求和非簡單請求瀏覽器

一  簡單請求緩存

1.1 區分條件:安全

只要知足一下兩大條件,屬於簡單請求:服務器

(1) 請求方法是如下三種方法之一:
        HEAD
        GET
        POST
(2)HTTP的頭信息不超出如下幾種字段:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain        

不一樣時知足上面兩個條件,就是非簡單請求

1.2 簡單請求的基本流程

瀏覽器直接發送CORS跨域請求,並在header信息中增長一個Origin字段,代表這是一個跨域的請求。

    <script>
        var url = 'http://www.lishanlei.cn/CorsTest/CorsTest.php';
        var xhr = new XMLHttpRequest();
        xhr.open('get', url, true);
        // xhr.setRequestHeader('X-Custom-Header', 'value');
        xhr.send();
    </script>

在上面的代碼中以get形式向www.lishanlei.cn進行跨域訪問。

上面的頭信息Origin字段用來講明本次請求來自哪一個源(協議+域名+端口)。服務器根據這個值,決定是否贊成此次請求。若是Origin指定的源,不在許可範圍內,服務器會返回一個正常的HTTP迴應,瀏覽器收到這個迴應發現這個迴應的頭信息沒有包含Access-Control-Allow-Origin字段,就知道錯了,從而會拋出一個錯誤,被XMLHttpRequestonerror回調函數捕獲。注意這種錯誤沒法經過狀態碼識別,此時HTTP迴應的狀態碼多是200

 

若是Origin指定的域名在許可範圍內,服務器返回的響應會多出幾個頭信息字段

Access-Control-Allow-Origin:該字段是必須的,其值多是請求時Origin字段的值,也多是一個*,表示接受任意域名請求。

Access-Control-Allow-Credentials:該字段可選,其值類型是布爾型,表示是否容許發送Cookie。默認狀況下Cookie不包括在CORS請求中。當設爲true時表示服務器明確許可,Cookie能夠包含在請求中一塊兒發送給服務器。

Access-Control-Allow-Headers:該字段必須,它是一個都好分割的字符串,代表服務器支持的全部頭信息字段

1.3 withCredentials屬性

默認狀況下,CORS請求默認不發送Cookie和Http認證信息,若是要把Cookie發送到服務器,首先要指定Access-Control-Alloe-Credentials字段,另外一方面,須要在AJAX請求中打開withCredentials屬性

var xml = new XMLHttpRequest();
xml.withCredentials = true;

若是沒有設置該屬性爲true,即便服務器統一發送Cookie,瀏覽器也不會發送。

當該屬性設置爲true時,即須要發送Cookie那麼在服務器中Access-Control-Allow-Origin就不能設置成*,必須指定嗎明確的與請求一致的域名,同時,Cookie依然遵循同源政策。

二  非簡單請求

當不一樣時知足區分條件的,就是非簡單請求。

2.1 預檢請求

非簡單請求的CORS請求,會在正式通訊前進行一次Http查詢請求,又稱預檢請求。

瀏覽器先請求服務器,當前網頁所在域名是否在服務器許可名單中以及可使用那些HTTP動詞和頭信息字段,當客戶端獲得確定答覆時,瀏覽器纔會正式發出XMLHttpRequest請求。

var url = 'http://www.lishanlei.cn/CorsTest/CorsTest.php';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

上面代碼中,請求方式是PUT,併發送一個自定義頭信息X-custom-Header,但在服務器的頭信息中沒有包含X-custom-Header,故瀏覽器報錯,只進行了一次預檢請求。

設置header中的Access-Control-Allow-Headers字段:

header('Access-Control-Allow-Headers:x-requested-with,content-type,X-Custom-Header');

再次訪問

瀏覽器發現這是一個非簡單請求,自動發出一個預檢請求,要求服務其確認這樣的請求,下面是這個預檢請求的HTTP頭信息:

預檢請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。

Access-Control-Request-Method:該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法。

Access-Control-Request-Headers:該字段是一個逗號分割的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段。

2.2預檢請求的迴應

當服務其收到預檢請求後,檢查了Origin,Access-Control-Request-Method等信息字段後,若是沒有問題,則確認容許跨源請求,就能夠作出了迴應。

Access-Control-Allow-Methods:該字段必須,其值是逗號分隔的一個字符串,代表服務器支持的全部跨域請求的方法。這是爲了不屢次預檢請求。

Access-Control-Max-Age:該字段是可選的,用來指定本次預檢請求的有效期,單位是秒。Access-Control-Max-Age:20,即容許緩存該條迴應20秒,再此期間不用發出另外一條預檢請求

若是瀏覽器否認了預檢請求,會返回一個正常的HTTP迴應,可是沒有任何CORS相關的頭信息字段。瀏覽器此時會認定服務器不一樣意預檢請求,觸發一個錯誤,被XMLHttpRequestonerror回調函數捕獲。

 

服務器端處理機制

服務器對於跨域請求的處理流程以下:

  1. 首先查看http頭部有無origin字段;
  2. 若是沒有,或者不容許,當成普通請求;
  3. 若是有且是容許的,再看是不是preflight(method=OPTIONS);
  4. 若是不是preflight(簡單請求),返回Allow-Origin,Allow-Credential等字段,並返回正常內容;
  5. 若是是preflight(非簡單請求),返回Allow-Headers,Allow-Methods等;

配置CORS規則

一  apache上配置CORS規則

Apache須要使用mod_headers模塊來激活HTTP頭設置,默認是激活的,只須要修改Apache配置文件中的/etc/apache2/sites-available/000-default.conf

1 開啓模塊 
sudo a2enmod headers 
2 編輯配置文件 
sudo vi /etc/apache2/sites-available/000-default.conf 
3 在虛擬主機Directory設置下添加 
Header set Access-Control-Allow-Origin *

 

與JSONP的比較

CORS和JSONP都是爲了使web瀏覽器可以跨源請求,使用目的相同,可是比JSONP更強大。JSONP只支持GET請求,而CORS支持全部類型的HTTP請求,不過JSONP的優點在於支持老式瀏覽器以及能夠向不支持CORS的網站跨源請求。

 

參考博文http://www.ruanyifeng.com/blog/2016/04/cors.html

                 https://blog.csdn.net/u014344668/article/details/54948546

相關文章
相關標籤/搜索