using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
namespace WebService.Controllers
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class TestController : ApiController
// Controller methods not shown...
对于 源 参数,请使用在其中部署 WebClient 应用程序的 URI。 这允许来自 WebClient 的跨域请求,同时仍然禁止所有其他跨域请求。 稍后,我将更详细地描述 [EnableCors] 的参数。
不要在 源 URL 末尾包含正斜杠。
重新部署更新的 WebService 应用程序。 无需更新 WebClient。 现在,来自 WebClient 的 AJAX 请求应成功。 允许使用 GET、PUT 和 POST 方法。
CORS 的工作原理
本部分介绍在 HTTP 消息级别 CORS 请求中发生的情况。 请务必了解 CORS 的工作原理,以便可以正确配置 [EnableCors] 属性,并根据需要进行故障排除。
CORS 规范引入了几个启用跨源请求的新 HTTP 标头。 如果浏览器支持 CORS,则会自动为跨域请求设置这些标头;无需在 JavaScript 代码中执行任何特殊操作。
下面是跨域请求的示例。 “Origin”标头为发出请求的网站提供域。
GET http://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: http://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: http://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
如果服务器允许请求,它将设置 Access-Control-Allow-Origin 标头。 此标头的值与 Origin 标头匹配,或者是通配符值“*”,表示允许任何源。
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Date: Wed, 05 Jun 2013 06:27:30 GMT
Content-Length: 17
GET: Test message
如果响应不包含 Access-Control-Allow-Origin 标头,AJAX 请求将失败。 具体来说,浏览器不允许该请求。 即使服务器返回成功的响应,浏览器也不会向客户端应用程序提供响应。
对于某些 CORS 请求,浏览器会在发送资源的实际请求之前发送一个名为“预检请求”的其他请求。
如果满足以下条件,浏览器可以跳过预检请求:
请求方法为 GET、HEAD 或 POST, 以及
应用程序不设置除 Accept、Accept-Language、Content-Language、Content-Type 或 Last-Event-ID 以外的任何请求 标头,
如果设置) 为下列项之一,则 Content-Type 标头 (:
application/x-www-form-urlencoded
multipart/form-data
text/plain
有关请求标头的规则适用于应用程序通过在 XMLHttpRequest 对象上调用 setRequestHeader 设置的标头。 (CORS 规范调用这些“作者请求标头”。) 浏览器可以设置的标头不适用于 浏览器 可以设置的标头,例如用户代理、主机或内容长度。
下面是预检请求的示例:
OPTIONS http://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: http://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0
预外部测试版请求使用 HTTP OPTIONS 方法。 它包括两个特殊标头:
Access-Control-Request-Method:将用于实际请求的 HTTP 方法。
Access-Control-Request-Headers: 应用程序 在实际请求上设置的请求标头列表。 再次 (,这不包括浏览器设置的标头。)
下面是一个示例响应,假设服务器允许请求:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 05 Jun 2013 06:33:22 GMT
响应包括一个 Access-Control-Allow-Methods 标头,该标头列出允许的方法,以及一个 Access-Control-Allow-Headers 标头,其中列出了允许的标头。 如果预检请求成功,浏览器会发送实际请求,如前所述。
通常用于测试预检 OPTIONS 请求的终结点的工具 (,例如 Fiddler 和 Postman) 默认情况下不会发送所需的 OPTIONS 标头。 确认 Access-Control-Request-Method
使用请求发送和 Access-Control-Request-Headers
标头,并且 OPTIONS 标头通过 IIS 到达应用。
若要将 IIS 配置为允许 ASP.NET 应用接收和处理 OPTION 请求,请在部分中将以下配置添加到应用的 web.config 文件中 <system.webServer><handlers>
:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
删除 OPTIONSVerbHandler
可防止 IIS 处理 OPTIONS 请求。 ExtensionlessUrlHandler-Integrated-4.0
替换允许 OPTIONS 请求访问应用,因为默认模块注册仅允许使用无扩展 URL 的 GET、HEAD、POST 和 DEBUG 请求。
[EnableCors] 的范围规则
可以为应用程序中的所有 Web API 控制器启用每个操作、每个控制器或全局 CORS。
若要为单个操作启用 CORS,请对操作方法设置 [EnableCors] 属性。 以下示例仅为 GetItem
该方法启用 CORS。
public class ItemsController : ApiController
public HttpResponseMessage GetAll() { ... }
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")]
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
public HttpResponseMessage PutItem(int id) { ... }
每个控制器
如果在控制器类上设置了 [EnableCors] ,则它适用于控制器上的所有操作。 若要禁用操作的 CORS,请将 [DisableCors] 属性添加到该操作。 以下示例为除以下 PutItem
各项方法启用 CORS。
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")]
public class ItemsController : ApiController
public HttpResponseMessage GetAll() { ... }
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
[DisableCors]
public HttpResponseMessage PutItem(int id) { ... }
若要为应用程序中的所有 Web API 控制器启用 CORS,请将 EnableCorsAttribute 实例传递给 EnableCors 方法:
public static class WebApiConfig
public static void Register(HttpConfiguration config)
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
// ...
如果在多个范围内设置属性,则优先级顺序为:
设置允许的源
[EnableCors] 属性的源参数指定允许哪些源访问资源。 该值是允许的源的逗号分隔列表。
[EnableCors(origins: "http://www.contoso.com,http://www.example.com",
headers: "*", methods: "*")]
还可以使用通配符值“*”允许来自任何源的请求。
在允许来自任何源的请求之前,请仔细考虑。 这意味着,任何网站都可以对 Web API 进行 AJAX 调用。
// Allow CORS for all origins. (Caution!)
[EnableCors(origins: "*", headers: "*", methods: "*")]
设置允许的 HTTP 方法
[EnableCors] 属性的方法参数指定允许哪些 HTTP 方法访问资源。 若要允许所有方法,请使用通配符值“*”。 以下示例仅允许 GET 和 POST 请求。
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "get,post")]
public class TestController : ApiController
public HttpResponseMessage Get() { ... }
public HttpResponseMessage Post() { ... }
public HttpResponseMessage Put() { ... }
本文前面介绍了预检请求如何包括 Access-Control-Request-Headers 标头,其中列出了应用程序设置的 HTTP 标头, (所谓的“作者请求标头”) 。 [EnableCors] 属性的标头参数指定允许哪些作者请求标头。 若要允许任何标头,请将 标头 设置为“*”。 若要允许特定标头,请将 标头 设置为允许标头的逗号分隔列表:
[EnableCors(origins: "http://example.com",
headers: "accept,content-type,origin,x-my-header", methods: "*")]
但是,浏览器在设置 Access-Control-Request-Header 的方式中并不完全一致。 例如,Chrome 当前包含“origin”。 FireFox 不包括标准标头(如“Accept”),即使应用程序在脚本中设置它们也是如此。
如果将 标头 设置为除“*”以外的任何内容,则应至少包括“accept”、“content-type”和“origin”,以及要支持的任何自定义标头。
默认情况下,浏览器不会向应用程序公开所有响应标头。 默认情况下可用的响应头包括:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
CORS 规范调用这些 简单的响应标头。 若要使其他标头可用于应用程序,请设置 [EnableCors] 的公开Headers 参数。
在以下示例中,控制器的方法设置名为“X-Custom-Header”的 Get
自定义标头。 默认情况下,浏览器不会在跨源请求中公开此标头。 若要使标头可用,请在 公开的Headers 中包含“X-Custom-Header”。
[EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-Custom-Header")]
public class TestController : ApiController
public HttpResponseMessage Get()
var resp = new HttpResponseMessage()
Content = new StringContent("GET: Test message")
resp.Headers.Add("X-Custom-Header", "hello");
return resp;
在跨源请求中传递凭据
凭据需要在 CORS 请求中进行特殊处理。 默认情况下,浏览器不会发送具有跨源请求的任何凭据。 凭据包括 Cookie 以及 HTTP 身份验证方案。 若要发送具有跨域请求的凭据,客户端必须将 XMLHttpRequest.withCredentials 设置为 true。
直接使用 XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;
在 jQuery 中:
$.ajax({
type: 'get',
url: 'http://www.example.com/api/test',
xhrFields: {
withCredentials: true
此外,服务器必须允许凭据。 若要在 Web API 中允许跨域凭据,请将 [EnableCors] 属性上的 SupportsCredentials 属性设置为 true:
[EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*",
methods: "*", SupportsCredentials = true)]
如果此属性为 true,HTTP 响应将包含 Access-Control-Allow-Credentials 标头。 此标头告知浏览器服务器允许跨源请求的凭据。
如果浏览器发送凭据,但响应不包括有效的 Access-Control-Allow-Credentials 标头,则浏览器不会向应用程序公开响应,并且 AJAX 请求失败。
请务必注意将 SupportsCredentials 设置为 true,因为这意味着另一个域中的网站可以代表用户将登录用户的凭据发送到 Web API,而无需用户知道。 CORS 规范还指出,如果 SupportsCredentials 为 true,则将源设置为“*”无效。
自定义 CORS 策略提供程序
[EnableCors] 属性实现 ICorsPolicyProvider 接口。 可以通过创建派生自 Attribute 并实现 ICorsPolicyProvider 的类来提供自己的实现。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class MyCorsPolicyAttribute : Attribute, ICorsPolicyProvider
private CorsPolicy _policy;
public MyCorsPolicyAttribute()
// Create a CORS policy.
_policy = new CorsPolicy
AllowAnyMethod = true,
AllowAnyHeader = true
// Add allowed origins.
_policy.Origins.Add("http://myclient.azurewebsites.net");
_policy.Origins.Add("http://www.contoso.com");
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
return Task.FromResult(_policy);
现在,你可以应用将 放置 [EnableCors] 的任何位置的属性。
[MyCorsPolicy]
public class TestController : ApiController
.. //
例如,自定义 CORS 策略提供程序可以从配置文件读取设置。
作为使用属性的替代方法,可以注册创建 ICorsPolicyProviderFactory 对象的 ICorsPolicyProviderFactory 对象。
public class CorsPolicyFactory : ICorsPolicyProviderFactory
ICorsPolicyProvider _provider = new MyCorsPolicyProvider();
public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
return _provider;
若要设置 ICorsPolicyProviderFactory,请在启动时调用 SetCorsPolicyProviderFactory 扩展方法,如下所示:
public static class WebApiConfig
public static void Register(HttpConfiguration config)
config.SetCorsPolicyProviderFactory(new CorsPolicyFactory());
config.EnableCors();
// ...
浏览器支持
Web API CORS 包是服务器端技术。 用户的浏览器还需要支持 CORS。 幸运的是,所有主要浏览器的当前版本都包括 对 CORS 的支持。