首先基於安全的緣由,瀏覽器是存在同源策略這個機制的,同源策略阻止從一個源加載的文檔或腳本獲取或設置另外一個源加載的文檔的屬性。git
對於同源必需要求URL在以下幾個方面相同:github
JSONP是跨域訪問的一種方法。在web開發中咱們常常會引用第三方的js文件,這個時候咱們會發現瀏覽器並無攔截。JSONP就是利用向網頁中添加script標籤的方式去進行跨域訪問。web
通常處理在處理JSONP的時候會將回調函數名與參數做爲QueryString傳給服務端,服務端再根據上傳的函數名生成js回傳給客戶端。api
因爲採用的是添加script標籤的方式,因此JSONP只能經過GET方法訪問服務器。另外因爲服務端要根據上傳的函數名生成js,因此JSONP方法獲得的並非數據,而是方法的調用。跨域
在Demo中我寫了一個JSONP的服務端生成與客戶端調用方法。瀏覽器
對於CORSAccess-Control-Allow-Origin安全
引用System.Web.Http.Cors庫服務器
經過NuGet管理添加System.Web.Http.Cors,我引用的庫名爲:Microsoft ASP.NET Web API 2.2 Cross-Origin Support網絡
引用庫後,首先在WebApiConfig.Register方法中首行,添加一句 config.EnableCors()(記得必定要添加到首行。開始我也是添加在末行,但一直運行不成功,花了好半天功夫,才找到是這個問題。這個之後有時間再看看Cors內部的實現原理,按說不該該出現這樣的問題。)。cors
public static void Register(HttpConfiguration config) { // Web API 配置和服務 config.EnableCors(); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); }
System.Web.Http.Cors庫對於Cors控制也是經過特性(Attribute)來實現的。System.Web.Http.Cors庫提供了兩個與Cors的特性:EnableCorsAttribute與DisableCorsAttribute,這兩個特性都是基於Controller與Action的。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public sealed class DisableCorsAttribute : Attribute, ICorsPolicyProvider { public DisableCorsAttribute(); public Task<System.Web.Cors.CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken); }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public sealed class EnableCorsAttribute : Attribute, ICorsPolicyProvider { public EnableCorsAttribute(string origins, string headers, string methods); public EnableCorsAttribute(string origins, string headers, string methods, string exposedHeaders); public IList<string> ExposedHeaders { get; } public IList<string> Headers { get; } public IList<string> Methods { get; } public IList<string> Origins { get; } public long PreflightMaxAge { get; set; } public bool SupportsCredentials { get; set; } public Task<System.Web.Cors.CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken); }
EnableCorsAttribute與DisableCorsAttribute都實現了ICorsPolicyProvider接口。但 DisableCorsAttribute沒有別的屬性與構造函數,它的使用場景大體爲當Controller已經被添加EnableCorsAttribute後,爲個別不作Cors的Action禁用掉。
EnableCorsAttribute的與響應頭部信息相對應,其對應關係以下:
屬性 |
頭部信息 |
備註 |
Origins |
Allow-Control-Allow-Origin |
CORS容許的請求域名,用逗號(,)去區他不一樣的域名,如:http://localhost:64299,http://www.baidu.com。 對於沒有域名,能夠用星號(*) |
Methods |
Allow-Control-Allow-Method |
CORS容許的請求方法,用法同Origins |
Headers |
Allow-Control-Allow-Headers |
|
ExposedHeaders |
Allow-Control-Expose-Header |
|
PreflightMaxAge |
Allow-Control-Max-Age |
|
SupportsCredentials |
Allow-Control-Allow-Credentials |
在測試過程當中我發如今火狐上可以正常運行,但到了IE是就不行了,通過一番查找,發現要在要添加一句話:
jQuery.support.cors = true;
但加了這句話後,雖然/api/demo/GetFigureByCors能夠調的,但/api/demo/GetFigureNoCors也能夠調用了。到這又鬱悶了,這又是要搞那樣。又通過一番折騰,才發現這個時候jQuery並非用的XMLHttpRequest,而是採用的IE自帶的XDomainRequest組件,而且該組件只支持IE8及以上。
在Demo中出於對同源的規則的考慮,我定義了兩個Web項目:API_15與API_15.Web。API_15中的DemoController分別定義的三個方法GetFigureByJsonP,GetFigureNoCors,GetFigureByCors分別用於JSONP,非Cors,Cors調用。
public class DemoController : ApiController { public HttpResponseMessage GetFigureByJsonP(string callback) { StringBuilder result = new StringBuilder(); result.Append("callback("); result.Append(JsonConvert.SerializeObject(FigureManager.Figures)); result.Append(")"); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(result.ToString()) }; } public IEnumerable<Figure> GetFigureNoCors() { return FigureManager.Figures; } //[EnableCors(origins:"*",headers: "*",methods:"*")] [EnableCors(origins: "http://localhost:64299,http://www.baidu.com", headers: "GET,POST", methods: "*")] public IEnumerable<Figure> GetFigureByCors() { return FigureManager.Figures; } }
在API_15.Web項目中只定義了一個頁面,經過jQuery的AJAX去調用API_15中三個Action。
Github: https://github.com/BarlowDu/WebAPI(API_15,API_15.Web)