.NET Framework4.8中ASP.NET MVC OPTIONS预请求未触发处理问题
问题原因及解决方案
原因分析
- IIS默认拦截OPTIONS请求:IIS自带的
OPTIONSVerbHandler会自行处理OPTIONS预请求,不会将其转发到ASP.NET请求管道,导致Application_BeginRequest和MVC ActionFilter都无法捕获到这类请求。 - MVC ActionFilter的局限性:ActionFilter仅对匹配到控制器Action的请求生效,而OPTIONS预请求通常没有对应的Action路由,因此不会触发
OnActionExecuting方法。
解决步骤
1. 修改Web.config,让OPTIONS请求进入ASP.NET管道
在<system.webServer>节点下添加或修改处理器配置,替换默认的OPTIONS处理逻辑:
<system.webServer> <handlers> <!-- 移除默认的OPTIONS处理器 --> <remove name="OPTIONSVerbHandler" /> <!-- 添加自定义OPTIONS处理器,将请求转发给ASP.NET --> <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ManagedPipelineHandler" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="None" /> </handlers> </system.webServer>
2. 在Global.asax中完整处理CORS逻辑
修改Application_BeginRequest方法,覆盖OPTIONS预请求处理和动态Origin头设置:
protected void Application_BeginRequest(object sender, EventArgs e) { var context = HttpContext.Current; var request = context.Request; var response = context.Response; // 处理OPTIONS预请求 if (request.HttpMethod == "OPTIONS") { // 设置允许的请求方法(根据实际接口支持的方法调整) response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); // 设置允许的请求头(*表示允许所有,也可指定具体头如Content-Type) response.Headers.Add("Access-Control-Allow-Headers", "*"); // 设置预请求结果的缓存时长(单位:秒) response.Headers.Add("Access-Control-Max-Age", "86400"); // 直接返回200状态,终止后续管道执行 response.StatusCode = 200; } // 动态设置Access-Control-Allow-Origin var needsCustomOrigin = ConfigurationManager.ConnectionStrings["CustomOrigin"]?.ConnectionString ?? ""; if (!string.IsNullOrWhiteSpace(needsCustomOrigin)) { string originHeader = null; // 优先获取Origin头 if (request.Headers.AllKeys.Contains("Origin")) { originHeader = request.Headers["Origin"]; } // 无Origin时从Referer提取源域名(需去除路径部分) else if (request.Headers.AllKeys.Contains("Referer")) { try { var refererUri = new Uri(request.Headers["Referer"]); originHeader = $"{refererUri.Scheme}://{refererUri.Host}:{refererUri.Port}"; } catch (UriFormatException) { // 处理无效Referer的情况 originHeader = string.Empty; } } if (!string.IsNullOrWhiteSpace(originHeader)) { // 避免重复添加响应头 if (!response.Headers.AllKeys.Contains("Access-Control-Allow-Origin")) { response.Headers.Add("Access-Control-Allow-Origin", originHeader); } // 如果需要支持带凭据的请求(如Cookie),添加以下头 response.Headers.Add("Access-Control-Allow-Credentials", "true"); } } // OPTIONS请求处理完成后直接结束响应 if (request.HttpMethod == "OPTIONS") { response.End(); } }
3. 移除无效的ActionFilter
由于ActionFilter无法捕获无路由匹配的OPTIONS请求,之前定义的MyActionFilterAttribute可以直接移除,无需再使用。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

