调用ASP.NET Core Web API时仅服务器异常触发CORS错误(Angular 6)
这个问题其实很常见——正常请求时CORS头能正确添加,但服务器抛出500异常时,默认的错误响应没有带上CORS头,导致客户端浏览器触发CORS错误。
为什么会这样?
当你的API正常处理请求时,请求会完整经过ASP.NET Core的中间件管道:CORS中间件会在响应中添加Access-Control-Allow-Origin等头,然后返回给客户端。但如果服务器抛出未处理的异常(不管是在控制器动作里,还是中间件、模型绑定阶段),ASP.NET Core的默认错误处理机制会接管响应,这时候之前的CORS中间件可能没机会给错误响应添加头,或者默认的错误响应直接跳过了CORS头的设置。
哪怕你配置了AllowAllPolicy或者全局CORS,只要错误响应没有被正确处理并添加CORS头,浏览器就会认为这是跨域非法响应。
解决方法
你需要确保所有响应(包括错误响应)都带上必要的CORS头,这里有几种可靠的实现方式:
1. 全局异常处理中间件(推荐)
在请求管道最前面添加自定义异常处理中间件,捕获所有异常并手动添加CORS头,同时返回友好的错误信息:
// 在Startup.Configure方法中,先配置异常处理(要放在其他中间件之前) app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { // 获取异常详情 var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>(); var errorMessage = exceptionFeature?.Error?.Message ?? "未知服务器错误"; // 设置响应状态码和内容类型 context.Response.StatusCode = StatusCodes.Status500InternalServerError; context.Response.ContentType = "application/json"; // 手动添加CORS头(可以根据你的策略动态获取,这里直接写死示例) context.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200"); // 如果需要允许凭证,加上这行 context.Response.Headers.Add("Access-Control-Allow-Credentials", "true"); // 返回异常详情给客户端 await context.Response.WriteAsJsonAsync(new { Status = "Error", Message = errorMessage }); }); }); // 然后再配置CORS中间件(位置要在UseRouting之后,UseAuthorization之前) app.UseCors("AllowAllPolicy"); // 其他中间件配置... app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
2. MVC全局异常过滤器
如果你的项目是ASP.NET Core MVC,可以实现一个异常过滤器,在控制器抛出异常时自动添加CORS头:
public class CorsExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { // 添加CORS头 context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200"); context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true"); // 构造错误响应 context.Result = new ObjectResult(new { Status = "Error", Detail = context.Exception.Message }) { StatusCode = StatusCodes.Status500InternalServerError }; context.ExceptionHandled = true; } }
然后在Startup.ConfigureServices中注册这个过滤器:
services.AddControllers(options => { options.Filters.Add<CorsExceptionFilter>(); });
3. 检查中间件执行顺序
确保你的CORS中间件UseCors放在正确的位置:必须在UseRouting之后,UseAuthorization之前。这样可以保证路由匹配后,CORS策略能被正确应用,即使后续中间件抛出异常,部分场景下CORS头已经被添加。
关键提醒
不要依赖默认的错误响应(比如ASP.NET Core自带的黄色错误页),因为它们不会自动包含CORS头。通过全局异常处理统一管理所有错误响应,既能保证CORS头的存在,也能让客户端拿到清晰的错误信息。
内容的提问来源于stack exchange,提问作者Lenni Lobel

