React与ASP.NET Core WebAPI间歇性CORS问题排查求助
React + ASP.NET Core WebAPI 间歇性CORS问题排查与解决
问题现象
我有React前端和ASP.NET Core WebAPI后端,已在WebAPI的Startup.cs中配置CORS,首次加载页面时可正常与API交互,但存在以下间歇性问题:
- 多标签页打开网站、会话超时或执行登出操作时,会触发CORS错误
- 错误提示:
Access to fetch at ‘/api/lastvisited' from origin 'https://localhost.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. - 请求报错:
POST https://localhost/api/v1/lastvisited net::ERR_FAILED 302 (anonymous) - 代码报错:
Uncaught (in promise) TypeError: Failed to fetch
相关代码
WebAPI Program.cs
namespace WebAPI { public static class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); } }
WebAPI Startup.cs
namespace WebAPI { public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment) { Configuration = configuration; WebHostEnvironment = webHostEnvironment; } public IConfiguration Configuration { get; } public IWebHostEnvironment WebHostEnvironment { get; } public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddCors(); services.AddHttpContextAccessor(); services.AddScoped<HttpContextAccessor>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime appLifetime) { AppHttpContext.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>()); //Allow cors domain string[] CORSAllowedDomains = Configuration.GetSection("CORSAllowedDomains").Get<string[]>(); app.UseCors( options => options.WithOrigins( CORSAllowedDomains).WithMethods("PUT", "DELETE", "GET", "POST").AllowAnyMethod().AllowAnyHeader().AllowCredentials().SetIsOriginAllowedToAllowWildcardSubdomains() ); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } if (!WebHostEnvironment.IsEnvironment("Local")) { app.UseForwardedHeaders(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } } }
React Header组件代码
export class Header extends React.Component { constructor(props) { this.state = { loading: true }; } onLogout() { const d = new Date(); let lastVisitedDateTime = d.toLocaleString(); lastVisitedDateTime = lastVisitedDateTime.replace(",", ""); const data = { lastVisitedDateTime }; const SERVICE_URL = "/lastvisiteddateandtime"; fetch(SERVICE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify(data) }) .then((response) => response.json()) .catch((error) => console.error("Error:", error)); window.sessionStorage.clear(); window.location.href = "/"; } render() { return ( <Link onClick={this.onLogout.bind(this)}> Logout</Link> </div> ); } } export default Header;
解决方案
1. 修正中间件执行顺序
ASP.NET Core中间件顺序直接影响CORS头的生效时机,UseCors必须放在UseRouting之前,且早于UseHttpsRedirection、UseStaticFiles等中间件。同时移除重复的WithMethods配置:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime appLifetime) { AppHttpContext.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>()); // 优先配置CORS,确保在路由处理前生效 string[] CORSAllowedDomains = Configuration.GetSection("CORSAllowedDomains").Get<string[]>(); app.UseCors(options => options .WithOrigins(CORSAllowedDomains) .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() .SetIsOriginAllowedToAllowWildcardSubdomains()); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } if (!WebHostEnvironment.IsEnvironment("Local")) { app.UseForwardedHeaders(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); }
2. 处理302重定向导致的CORS失效
错误中的302状态码说明会话超时后API自动重定向到登录页,而重定向后的地址不在CORS允许列表中,导致报错。需修改API返回401而非302:
- 添加全局授权过滤器:
public class NoRedirectAuthorizationFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { if (!context.HttpContext.User.Identity.IsAuthenticated) { context.Result = new UnauthorizedResult(); // 返回401状态码,避免重定向 } } } // 在ConfigureServices中注册过滤器 services.AddControllers(options => { options.Filters.Add<NoRedirectAuthorizationFilter>(); });
- 前端处理401错误:
fetch(SERVICE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify(data) }) .then((response) => { if (!response.ok) { if (response.status === 401) { window.sessionStorage.clear(); window.location.href = "/"; } throw new Error('请求失败'); } return response.json(); }) .catch((error) => console.error("Error:", error));
3. 确保登出请求完成后再跳转
当前登出逻辑中,fetch异步请求未完成就执行页面跳转,导致请求中断触发异常。修改为异步等待请求完成:
async onLogout() { const d = new Date(); let lastVisitedDateTime = d.toLocaleString().replace(",", ""); const data = { lastVisitedDateTime }; const SERVICE_URL = "/lastvisiteddateandtime"; try { await fetch(SERVICE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify(data) }); } catch (error) { console.error("Error:", error); } finally { window.sessionStorage.clear(); window.location.href = "/"; } }
4. 验证CORS域名配置
确保CORSAllowedDomains中的域名与前端实际Origin完全匹配,包括协议(http/https)、域名、端口,例如前端是https://localhost.net,配置中需完整填写该地址。
内容的提问来源于stack exchange,提问作者TestUser
相关产品推荐
相关产品推荐

