標籤:
CORS概念
跨域資源共用 (CORS) 是一種全球資訊網協會 (W3C) 規範(通常被認為是 HTML5 的一部分),它可讓 JavaScript 克服由瀏覽器施加的同域策略安全限制。 所謂同域策略,就是 JavaScript 只能對包含網頁的同一個域進行 AJAX 回調(其中,“域”就是主機名稱、協議和連接埠號碼的組合)。 例如,http://foo.com 中某個網頁上的 JavaScript 無法對 http://bar.com(或 http://www.foo.com、https://foo.com 或 http://foo.com:999 等)進行 AJAX 調用。
CORS 可讓伺服器指明允許哪些域對它們進行調用,從而放寬這種限制。 CORS 是由瀏覽器強制執行的,並且必須在伺服器上實現,而最新版本的 ASP.NET Web API 2 全面支援 CORS。 通過 Web API 2,您可以對策略進行配置以允許不同域的 JavaScript 用戶端訪問您的 API。
CORS 基本資料
由於 Web API 完全按照該規範來實現,因此,為了使用 Web API 中的新 CORS 功能,詳細瞭解 CORS 本身將大有協助。 這些詳細內容現在看起來可能都是理論之談,但對於以後瞭解 Web API 中的可用設定來說將十分有用:在您調試 CORS 時,這些內容有助於您更快速地解決問題。
CORS 的一般機制是,當 JavaScript 嘗試進行跨域 AJAX 調用時,瀏覽器會通過在 HTTP 要求中發送標題(如“Origin”)來“詢問”伺服器是否允許進行這樣的調用。 伺服器通過在響應中返回 HTTP 標題(如“Access-Control-Allow-Origin”)指明允許的操作。 這種許可權檢查將針對用戶端調用的每個不同 URL 進行,這就意味著不同的 URL 可以具有不同許可權。
除域之外,CORS 還可以讓伺服器指明允許使用的 HTTP 方法、用戶端可以發送的 HTTP 要求標題、用戶端可以讀取的 HTTP 響應標題以及是否允許瀏覽器自動發送或接收憑據(Cookie 或授權標頭)。 其他請求和響應標題指明允許使用其中的哪些功能。 圖 1 總結了這些標題(請注意,一些功能沒有在響應中發送的標題,僅有響應)。
圖 1 CORS HTTP 標題
許可權/功能 |
請求標題 |
響應標題 |
域 |
域 |
Access-Control-Allow-Origin |
HTTP 方法 |
Access-Control-Request-Method |
Access-Control-Allow-Method |
請求標題 |
Access-Control-Request-Headers |
Access-Control-Allow-Headers |
響應標題 |
|
Access-Control-Expose-Headers |
憑據 |
|
Access-Control-Allow-Credentials |
緩衝預檢響應 |
|
Access-Control-Max-Age |
瀏覽器可通過兩種不同的方式向伺服器請求這些許可權:簡單 CORS 請求和預檢 CORS 請求。
Web API 2 對 CORS 的支援
Web API 中對 CORS 的支援是一個完整架構,允許應用程式定義 CORS 請求的許可權。 該架構圍繞一個策略方案展開,該策略方案可讓您指定針對進入應用程式的任何給定請求而允許的 CORS 功能。
首先,為了擷取該 CORS 架構,您必須從 Web API 應用程式程式引用 CORS 庫(預設情況下,Visual Studio 2013 中的任何 Web API 模板都不引用這些庫)。 該 Web API CORS 架構通過 NuGet 作為 Microsoft.AspNet.WebApi.Cors 程式包提供。 早 nuget中輸入
Install-Package Microsoft.AspNet.WebApi.Cors
注意 Web api 2對,net framework的要求必須是4.5以上,安裝完上面的package後,會發現引用中多了兩個重要的包,如所示
接下來,為了表達該策略,Web API 提供了一個名為 EnableCorsAttribute 的自訂屬性類。 此類包含允許的網域、HTTP 方法、請求標題、響應標題以及是否允許使用憑據等方面的屬性(它們對前面所述的 CORS 規範的所有詳細資料進行建模)。
最後,為了讓 Web API CORS 架構處理 CORS 請求並發出適當的 CORS 響應標題,該類必須檢查進入應用程式的每個請求。 Web API 通過訊息處理常式提供用於這種攔截操作的擴充點。 Web API CORS 架構會相應地實現一個名為 CorsMessageHandler 的訊息處理常式。 對於 CORS 請求,該處理常式會查詢在所調用方法的屬性中表達的策略,並發出適當的 CORS 響應標題。
EnableCorsAttribute。EnableCorsAttribute 類就是應用程式表達其 CORS 策略的方式。EnableCorsAttribute 類有一個可接受三個或四個參數的重載建構函式。 這些參數(依次)為:
- 允許域列表
- 允許請求標題列表
- 允許 HTTP 方法列表
- 允許響應標題列表(可選)
還有一個允許使用憑據的屬性 (SupportsCredentials) 以及另一個用於指定預檢緩衝期間值的屬性 (PreflightMaxAge)。
以vs2013建立的預設api程式為例,建完webapi引用程式後在Controller檔案夾下會自動產生兩個控制區,一個HomeController和一個ValueController,我們主要看一下ValueControll,這個控制器繼承了ApiController,可見是一個webapi,我們在valueController上添加一個全域的 EnableCors屬性,以試它支援跨域,如所示
請注意,每個建構函式參數都是一個字串。 通過指定逗號分隔列表,可以表示多個值。 如果您想允許所有域、請求標題或 HTTP 方法,則可以使用“*”作為值(對於響應標題仍須顯式指定)。
除在方法層級應用 EnableCors 屬性外,還可以在類層級應用該屬性,或將其全域應用於應用程式。 應用該屬性的層級會在 Web API 代碼中為該層級及下面層級的所有請求配置 CORS。 例如,如果在方法層級應用該策略,則該策略僅應用於該操作的請求,而如果在類層級應用該策略,則該策略將應用於對該控制器的所有請求。 最後,如果全域應用該策略,則該策略將應用於所有請求。
如果在多個位置存在策略,則會使用“最接近的”屬性,並忽略其他屬性(優先順序是方法、類、全域)。 如果您已在較進階別上應用策略,但隨後想在較低層級上排除某一請求,則可以使用名為 DisableCorsAttribute 的另一個屬性類。 此屬性實質上是一個沒有允許許可權的策略。
如果在您不想允許 CORS 的控制器上有其他方法,則有兩個選擇。 首先,您可在 HTTP 方法列表中顯式指定。 或者,您可以保留萬用字元,但使用 DisableCors 屬性來排除 Delete 方法。
CorsMessageHandler。必須為 CORS 架構啟用 CorsMessageHandler,才能執行其為評估 CORS 策略並發出 CORS 響應標題而攔截請求的工作。 訊息處理常式的啟用通常是在應用程式的 Web API 配置類中通過調用 EnableCors 擴充方法進行的:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); //啟用跨域 config.EnableCors(); } }
在瀏覽器中輸入http://localhost:19881/api/values出現如下,說明該weapi已經可用。
那麼接下來,我們就要測試跨域了,建立一個mvc應用程式,制定連接埠號碼為19894
其中home/index頁面的代碼如下所示
@{ Layout = null;}<!DOCTYPE html><html><head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Scripts/jquery-1.8.2.min.js"></script></head><body> <div> <input type="button" id="cros" value="擷取跨域" /> <div id="msg"></div> </div> <script type="text/javascript"> $(function () { $("#cros").click(function () { $.ajax({ url: "http://localhost:19881/api/values", type: "get", success: function (d) { $("#msg").html(d) } }); }); }); </script></body></html>
代碼很簡單,就防放置一個按鈕,用ajax的方式請求不同域下的webapi,返回結果如所示
可以看出,其實瀏覽器發出了兩次請求。
自訂策略
從前面的樣本可明顯看到,域列表(如果未使用萬用字元)是一個編譯到 Web API 代碼中的靜態列表。 雖然這樣做在開發過程中或在特定情況下可能行得通,但如果需要動態確定域列表或其他許可權(比如,從資料庫擷取),則靜態列表就不夠用了。
明天在給大家介紹 WebApi自訂跨域策略,就是把域存在資料庫或者設定檔中,程式可以動態修改允許的網域的請求~~
ASP.NET Web API 2 對 CORS 的支援