如何在.NET 6中实现非API请求重定向至Angular路由
Azure Linux App Service页面刷新404:替代HashLocationStrategy的.NET 6重定向方案
问题背景
在Azure Linux App Service生产环境中,前端单页应用刷新页面时会返回404错误。之前通过在app.routing.module.ts中启用HashLocationStrategy解决了问题,但该方案会导致URL带#号,不利于SEO。现在希望撤销该路由策略修改,转而通过.NET 6 API后端处理路由重定向,但尝试app.MapWhen()或修改app.MapControllers()为app.UseEndpoints(options => options.MapControllers())均未成功。
当前代码
Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpsRedirection(options => options.HttpsPort = 443); // Add services to the container. builder.Services.AddCors(options => options.AddPolicy("Default", policyBuilder => { policyBuilder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }) ); builder.Services.AddControllers(); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(o => { o.SaveToken = true; o.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes( builder.Configuration .GetSection(ApplicationSettings.Section) .GetValue<string>("JWT:Secret"))) }; }); builder.Services.AddSwaggerGen(config => { config.SwaggerDoc("Backend", new OpenApiInfo { Title = "Backend", Version = "0.1"}); config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Please enter a valid token", Name = "Authorization", Type = SecuritySchemeType.Http, BearerFormat = "JWT", Scheme = "Bearer" }); var securityRequirement = new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, Array.Empty<string>() } }; config.AddSecurityRequirement(securityRequirement); }); builder.Services.Configure<ApplicationSettings>( builder.Configuration.GetSection(ApplicationSettings.Section)); builder.Services.AddDbContext<InstituteDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("Database"))); // Repositories builder.Services.AddScoped<ICareCategoryRepository, CareCategoryRepository>(); builder.Services.AddScoped<ICareRepository, CareRepository>(); builder.Services.AddScoped<IUserRepository, UserRepository>(); builder.Services.AddScoped<IReservationInfoRepository, ReservationInfoRepository>(); // Services builder.Services.AddScoped<ICareService, CareService>(); builder.Services.AddScoped<ICareCategoryService, CareCategoryService>(); builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddScoped<IReservationService, ReservationService>(); builder.Services.AddScoped<IReservationInfoService, ReservationInfoService>(); var app = builder.Build(); using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; var context = services.GetRequiredService<InstituteDbContext>(); context.Database.Migrate(); } app.UseMiddleware<ExceptionHandlerMiddleware>(); app.UseMiddleware<JwtMiddleware>(); app.UseMiddleware<AntiXssMiddleware>(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/Backend/swagger.json", "Backend"); }); } else { app.UseHttpsRedirection(); } app.UseRouting(); app.UseCors("Default"); app.UseAuthentication(); app.UseAuthorization(); app.UseDefaultFiles(); app.UseStaticFiles(); app.MapControllers(); app.Run();
.htaccess
RewriteEngine On # Redirection to HTTPS: RewriteCond %{HTTPS} !on RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # Redirection of requests to index.html RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d RewriteRule ^.*$ - [NC,L] # Redirect all non-file routes to index.html RewriteRule ^(?!.*\.).*$ index.html [NC,L]
解决方案
要实现无哈希路由且解决刷新404的问题,需要同时调整.NET 6中间件配置和.htaccess规则,确保API请求正常处理,前端路由请求回退到index.html。
1. 修改Program.cs添加回退路由
在app.MapControllers();之后添加条件回退路由,仅对非API路径的请求重定向到index.html,避免干扰API接口:
app.MapControllers(); // 添加回退路由:非API请求全部指向index.html app.MapWhen(context => !context.Request.Path.StartsWithSegments("/api"), builder => { builder.MapFallbackToFile("index.html"); }); app.Run();
同时确保中间件顺序正确:UseDefaultFiles必须在UseStaticFiles之前(你的代码中已经符合这个顺序),这样服务器会先尝试加载默认文档,再处理静态文件请求。
2. 调整.htaccess规则
原.htaccess的重写规则会将所有非文件/目录请求重定向到index.html,这会拦截API请求。修改规则,排除API路径:
RewriteEngine On # 强制HTTPS RewriteCond %{HTTPS} !on RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # 仅对非API路径处理回退 RewriteCond %{REQUEST_URI} !^/api RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d RewriteRule ^ index.html [NC,L]
关键说明
.htaccess的规则会在.NET中间件之前执行,所以必须先排除API路径,让这些请求直接到达.NET后端处理。.NET的MapWhen进一步确保非API请求都回退到index.html,让前端路由接管页面渲染,避免刷新404。- 这种方案保留了干净的URL结构,完全支持SEO,同时解决了单页应用刷新404的问题。
内容的提问来源于stack exchange,提问作者Scryper
相关产品推荐
相关产品推荐

