CORS概念javascript
跨域資源共享 (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 調用。html
CORS 可以讓服務器指明容許哪些域對它們進行調用,從而放寬這種限制。 CORS 是由瀏覽器強制執行的,而且必須在服務器上實現,而最新版本的 ASP.NET Web API 2 全面支持 CORS。 經過 Web API 2,您能夠對策略進行配置以容許不一樣域的 JavaScript 客戶端訪問您的 API。java
因爲 Web API 徹底按照該規範來實現,所以,爲了使用 Web API 中的新 CORS 功能,詳細瞭解 CORS 自己將大有幫助。 這些詳細內容如今看起來可能都是理論之談,但對於之後瞭解 Web API 中的可用設置來講將十分有用:在您調試 CORS 時,這些內容有助於您更快速地解決問題。jquery
CORS 的通常機制是,當 JavaScript 嘗試進行跨域 AJAX 調用時,瀏覽器會經過在 HTTP 請求中發送標頭(如「Origin」)來「詢問」服務器是否容許進行這樣的調用。 服務器經過在響應中返回 HTTP 標頭(如「Access-Control-Allow-Origin」)指明容許的操做。 這種權限檢查將針對客戶端調用的每一個不一樣 URL 進行,這就意味着不一樣的 URL 能夠具備不一樣權限。web
除域以外,CORS 還可讓服務器指明容許使用的 HTTP 方法、客戶端能夠發送的 HTTP 請求標頭、客戶端能夠讀取的 HTTP 響應標頭以及是否容許瀏覽器自動發送或接收憑據(Cookie 或受權標頭)。 其餘請求和響應標頭指明容許使用其中的哪些功能。 圖 1 總結了這些標頭(請注意,一些功能沒有在響應中發送的標頭,僅有響應)。ajax
圖 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 請求。api
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 類有一個可接受三個或四個參數的重載構造函數。 這些參數(依次)爲:
還有一個容許使用憑據的屬性 (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自定義跨域策略,就是把域存在數據庫或者配置文件中,程序能夠動態的修改容許的域的請求~~