经过一番挣扎,我发现处理 CORS 预检请求的唯一方法是使用一对 HttpModule 和 HttpHandler 来处理它。发送所需的标头是不够的。您必须尽早处理 OPTIONS 请求并且不允许它到达您的控制器,因为它会在那里失败。
我能做到这一点的唯一方法是使用 HttpModule。
我关注了这篇博文:
http://geekswithblogs.net/abhijeetp/archive/2016/06/04/adding-cors-support-for-asp.net--webapi-the-no-hassle.aspx
总结工作,这是代码:
namespace WebAPI.Infrastructure
{
using System;
using System.Web;
using System.Collections;
using System.Net;
public class CrossOriginModule : IHttpModule
{
public String ModuleName
{
get { return "CrossOriginModule"; }
}
public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
CrossOriginHandler.AddCorsResponseHeaders(context);
}
public void Dispose()
{
}
}
public class CrossOriginHandler : IHttpHandler
{
#region Data Members
const string OPTIONS = "OPTIONS";
const string PUT = "PUT";
const string POST = "POST";
const string PATCH = "PATCH";
static string[] AllowedVerbs = new[] { OPTIONS, PUT, POST, PATCH };
const string Origin = "Origin";
const string AccessControlRequestMethod = "Access-Control-Request-Method";
const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
const string AccessControlMaxAge = "Access-Control-Max-Age";
const string MaxAge = "86400";
#endregion
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
switch (context.Request.HttpMethod.ToUpper())
{
//Cross-Origin preflight request
case OPTIONS:
AddCorsResponseHeaders(context);
break;
default:
break;
}
}
#endregion
#region Static Methods
public static void AddCorsResponseHeaders(HttpContext context)
{
if (Array.Exists(AllowedVerbs, av => string.Compare(context.Request.HttpMethod, av, true) == 0))
{
var request = context.Request;
var response = context.Response;
var originArray = request.Headers.GetValues(Origin);
var accessControlRequestMethodArray = request.Headers.GetValues(AccessControlRequestMethod);
var accessControlRequestHeadersArray = request.Headers.GetValues(AccessControlRequestHeaders);
if (originArray != null &&
originArray.Length > 0)
response.AddHeader(AccessControlAllowOrigin, originArray[0]);
response.AddHeader(AccessControlAllowCredentials, bool.TrueString.ToLower());
if (accessControlRequestMethodArray != null &&
accessControlRequestMethodArray.Length > 0)
{
string accessControlRequestMethod = accessControlRequestMethodArray[0];
if (!string.IsNullOrEmpty(accessControlRequestMethod))
{
response.AddHeader(AccessControlAllowMethods, accessControlRequestMethod);
}
}
if (accessControlRequestHeadersArray != null &&
accessControlRequestHeadersArray.Length > 0)
{
string requestedHeaders = string.Join(", ", accessControlRequestHeadersArray);
if (!string.IsNullOrEmpty(requestedHeaders))
{
response.AddHeader(AccessControlAllowHeaders, requestedHeaders);
}
}
}
if (context.Request.HttpMethod == OPTIONS)
{
context.Response.AddHeader(AccessControlMaxAge, MaxAge);
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.End();
}
}
#endregion
}
}
并将它们添加到web.config
:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule" />
<add name="CrossOriginModule" preCondition="managedHandler" type="WebAPI.Infrastructure.CrossOriginModule, Your_Assembly_Name" />
</modules>
<handlers>
<remove name="WebDAV"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="CrossOrigin" verb="OPTIONS" path="*" type="WebAPI.Infrastructure.CrossOriginHandler, Your_Assembly_Name" />
</handlers>
<security>
<authorization>
<remove users="*" roles="" verbs=""/>
<add accessType="Allow" users="*" verbs="GET,HEAD,POST,PUT,PATCH,DELETE,DEBUG"/>
</authorization>
<requestFiltering>
<requestLimits maxAllowedContentLength="6000"/>
<verbs>
<remove verb="OPTIONS"/>
<remove verb="PUT"/>
<remove verb="PATCH"/>
<remove verb="POST"/>
<remove verb="DELETE"/>
</verbs>
</requestFiltering>
</security>
</system.webServer>
这适用于 Web API 和 MVC。