OWIN搭建C# WebApi 2.2 CORS预检正常但主请求跨域失败如何解决
问题根因
该情况的核心原因是预检请求由OWIN CORS中间件处理正常返回CORS头,但实际GET请求在进入控制器前就被其他管道节点/中间件拦截返回错误,响应未经过OWIN CORS中间件追加CORS头,所以浏览器报缺少CORS头错误,同时GET请求未命中控制器,GET响应的content-type为text/html也佐证了返回内容是服务端错误页面,不是接口的正常返回。
可行解决方案
1. 调整OWIN中间件注册顺序,确保CORS是首个注册的中间件
确保app.UseCors(CorsOptions.AllowAll)是Configuration方法中第一行执行的代码,避免后续中间件(比如认证中间件)在CORS中间件处理前就返回响应,导致CORS头缺失。
2. 移除WebApi自带的CORS配置避免冲突
检查WebApi配置类(一般是WebApiConfig.Register方法),确认没有重复配置config.EnableCors()相关逻辑,OWIN级别CORS和WebApi级别CORS同时启用会导致逻辑冲突。
3. 配置认证错误返回时追加CORS头
GET请求携带了Bearer token,大概率是JWT认证失败(比如token过期、签名错误)时,OWIN认证中间件直接返回401错误,未携带CORS头,需要在认证配置中添加如下兜底逻辑:
public void ConfigureAuth(IAppBuilder app) { // 保留现有认证配置,在末尾追加以下中间件 app.Use(async (context, next) => { await next.Invoke(); if (context.Response.StatusCode == 401 && context.Request.Headers.ContainsKey("Origin")) { context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { context.Request.Headers["Origin"] }); context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" }); } }); }
4. 临时关闭认证定位问题根源
临时注释掉ConfigureAuth(app)这行代码,测试GET请求是否能正常返回、CORS头是否存在,确认问题是否由认证中间件拦截导致。
5. Web.config补充CORS头兜底配置
在Web.config的system.webServer节点下添加如下配置,确保所有响应都携带CORS头:
<httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="https://localhost:4200" /> <add name="Access-Control-Allow-Headers" value="*" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /> <add name="Access-Control-Allow-Credentials" value="true" /> </customHeaders> </httpProtocol>
排查技巧
可直接用Postman调用该GET接口,传入相同的Authorization头,查看返回的状态码和具体错误内容,确认是401认证错误还是接口本身的500运行时错误,可快速定位问题。
内容的提问来源于stack exchange,提问作者Shyamal Parikh

