.NET Razor Pages如何将未知路由重定向至自定义404页面?
问题场景
我的应用里有3组页面,对应3种路由模式:
- 路径含1个额外部分:比如
{domain}/en/about-us/,这类页面的@page指令不带路由参数; - 路径含2个额外部分:比如
{domain}/en/product/{permalink}/,这类页面的@page指令带id参数,格式为@page "{id}/"; - 路径含3个额外部分:比如
{domain}/en/{category-permalink1}/{subcategory-permalink2}/{subsubcategory-permalink3}/,这类页面的@page指令格式为@page "/{maincat}/{subcat?}/{subsubcat?}/"。
目前正常路由都能工作,但当URL添加了额外部分(比如{domain}/{language_code}/{part2}/{part3}/{part4}/{part5})时,不会重定向到我自定义的404页面,反而跳转到系统默认的404页面。我之前尝试在RouteValueRequestCultureProvider里加逻辑处理,但没成功:
public class RouteValueRequestCultureProvider : IRequestCultureProvider { private readonly CultureInfo[] _cultures; public RouteValueRequestCultureProvider(CultureInfo[] cultures) { _cultures = cultures; } /// <summary> /// get {culture} route value from path string, /// </summary> /// <param name="httpContext"></param> /// <returns>ProviderCultureResult depends on path {culture} route parameter, or default culture</returns> public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext) { var defaultCulture = "en"; var path = httpContext.Request.Path; var routeValues = httpContext.Request.Path.Value.Split('/'); var pathParts = routeValues.Where(p => !string.IsNullOrEmpty(p)).ToArray(); if (pathParts.Length > 4) { httpContext.Response.StatusCode = 404; httpContext.Response.Redirect("/en/not-found/", true); } return Task.FromResult(new ProviderCultureResult(routeValues[1])); } }
解决办法
方法1:用Blazor通配符路由捕获无效请求(推荐)
Blazor支持通配符路由,可以专门做一个页面来捕获所有不匹配现有路由的请求,再重定向到自定义404:
- 创建
NotFoundCatchAll.razor页面,路由设为通配符:
@page "/{*path}" @inject NavigationManager NavManager @code { protected override void OnInitialized() { // 提取当前URL里的语言部分,没有的话用默认值en var pathSegments = NavManager.Uri.Split('/').Where(s => !string.IsNullOrEmpty(s)).ToArray(); var culture = pathSegments.Length > 0 ? pathSegments[0] : "en"; // 重定向到自定义404页面,forceLoad确保服务器端处理 NavManager.NavigateTo($"/{culture}/not-found/", forceLoad: true); } }
- 确保你的自定义404页面(比如
CustomNotFound.razor)路由正确:
@page "/{culture}/not-found/" <h1>404 - 页面不存在</h1> <p>您访问的路径无效,请检查后重试。</p>
这样所有不符合你3种路由模式的URL,都会被这个通配符页面捕获,然后跳转到你的自定义404。
方法2:服务器端中间件处理
如果需要在服务器层面拦截无效路由,写个自定义中间件:
public class InvalidRouteMiddleware { private readonly RequestDelegate _next; public InvalidRouteMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var pathParts = context.Request.Path.Value.Split('/') .Where(p => !string.IsNullOrEmpty(p)) .ToArray(); // 合法路径的部分数:2(语言+1段)、3(语言+2段)、4(语言+3段) if (pathParts.Length > 4) { var culture = pathParts.Length > 0 ? pathParts[0] : "en"; context.Response.StatusCode = StatusCodes.Status404NotFound; await context.Response.RedirectAsync($"/{culture}/not-found/"); return; } await _next(context); } }
然后在Program.cs里注册这个中间件,注意顺序要放在UseRouting之后,UseEndpoints之前:
app.UseRouting(); // 插入自定义中间件 app.UseMiddleware<InvalidRouteMiddleware>(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); });
为什么之前的方法没用?
RouteValueRequestCultureProvider的职责只是解析请求的文化信息,不是处理路由跳转。你在这个阶段修改响应,后续的路由中间件还会继续处理,可能会覆盖你设置的状态码或者重定向操作。另外,代码里routeValues[1]还可能因为路径过短抛出索引越界异常,得加判断。
内容的提问来源于stack exchange,提问作者Mehdi
相关产品推荐
相关产品推荐

