ASP.NET WebAPI 15 CORS

同源策略

首先基于安全的缘由,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另外一个源加载的文档的属性。git

对于同源必需要求URL在以下几个方面相同:github

  1. 网络协议(http与https不一样)
  2. 域名
  3. 端口(80与8080不一样)

 

 

JSONP

JSONP是跨域访问的一种方法。在web开发中咱们常常会引用第三方的js文件,这个时候咱们会发现浏览器并无拦截。JSONP就是利用向网页中添加script标签的方式去进行跨域访问。web

通常处理在处理JSONP的时候会将回调函数名与参数做为QueryString传给服务端,服务端再根据上传的函数名生成js回传给客户端。api

因为采用的是添加script标签的方式,因此JSONP只能经过GET方法访问服务器。另外因为服务端要根据上传的函数名生成js,因此JSONP方法获得的并非数据,而是方法的调用。跨域

Demo中我写了一个JSONP的服务端生成与客户端调用方法。浏览器

 

CORS

对于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的特性:EnableCorsAttributeDisableCorsAttribute,这两个特性都是基于ControllerAction的。

 

[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); 

 } 

 

 

 

EnableCorsAttributeDisableCorsAttribute都实现了ICorsPolicyProvider接口。但 DisableCorsAttribute没有别的属性与构造函数,它的使用场景大体为当Controller已经被添加EnableCorsAttribute后,为个别不作CorsAction禁用掉。

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

 

在测试过程当中我发如今火狐上可以正常运行,但到了IE是就不行了,通过一番查找,发现要在要添加一句话:

jQuery.support.cors = true;

 

但加了这句话后,虽然/api/demo/GetFigureByCors能够调的,/api/demo/GetFigureNoCors也能够调用了。到这又郁闷了,这又是要搞那样。又通过一番折腾,才发现这个时候jQuery并非用的XMLHttpRequest,而是采用的IE自带的XDomainRequest组件,而且该组件只支持IE8及以上。

 

 

关于Demo

Demo中出于对同源的规则的考虑,我定义了两个Web项目:API_15API_15.WebAPI_15中的DemoController分别定义的三个方法GetFigureByJsonPGetFigureNoCorsGetFigureByCors分别用于JSONP,非CorsCors调用。

 

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项目中只定义了一个页面,经过jQueryAJAX去调用API_15中三个Action

 

 

 

源码

   

Github: https://github.com/BarlowDu/WebAPI(API_15API_15.Web)