You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8 Web应用:如何将无效URL路由至主页?

问题背景

我们弃用了基于VB.NET的旧ASP.NET网站,替换为用C#开发、基于.NET 8的简易“横幅页面”应用,包含:

  • 主页
  • 功能请求的增删改页面

应用部署在IIS/Windows Server 2019上。旧应用有大量不同URL,需确保用户访问任何旧URL都导向新应用主页。尝试IIS“配置错误”功能无效,于是编写中间件处理404重定向,虽能成功重定向,但触发异常:

执行请求时发生未处理的异常。System.InvalidOperationException: 无法修改响应标头,因为响应已开始。

相关代码

RedirectPageNotFound.cs:

public class RedirectPageNotFound 
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RedirectPageNotFound> _logger;

    public RedirectPageNotFound(RequestDelegate next, ILogger<RedirectPageNotFound> logger) 
    {
        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context) 
    {
        await _next(context);

        if (context.Response.StatusCode == 404) 
        {
            _logger.LogInformation($"Handling 404 error for request {context.Request.Path}");
            context.Response.Redirect("/");
        } 
        else 
        {
            await _next(context);
        }
    }
}

Program.cs:

app.MapRazorPages();
app.MapControllers();
app.UseMiddleware<RedirectPageNotFound>();

问题1:如何修复System.InvalidOperationException异常?

异常的核心原因是:await _next(context)执行后,后续中间件可能已开始向客户端发送响应内容(写入响应体或设置标头),此时再调用Redirect会触发修改响应的限制。另外代码存在重复调用_next(context)的问题,会导致请求被处理两次。

修复方案

  1. 添加context.Response.HasStarted判断,仅在响应未开始时执行重定向
  2. 移除重复的_next调用
  3. 调整中间件注册顺序:将自定义中间件放在路由相关中间件之前,确保路由匹配前拦截请求

修正后代码

RedirectPageNotFound.cs:

public class RedirectPageNotFound 
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RedirectPageNotFound> _logger;

    public RedirectPageNotFound(RequestDelegate next, ILogger<RedirectPageNotFound> logger) 
    {
        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context) 
    {
        await _next(context);

        if (context.Response.StatusCode == 404 && !context.Response.HasStarted) 
        {
            _logger.LogInformation($"Handling 404 error for request {context.Request.Path}");
            // permanent=true发送301永久重定向,对SEO更友好
            context.Response.Redirect("/", permanent: true);
        }
    }
}

Program.cs:

// 先注册自定义404重定向中间件
app.UseMiddleware<RedirectPageNotFound>();
// 再注册路由相关中间件
app.MapRazorPages();
app.MapControllers();

问题2:是否存在更优的方式将无效URL路由至主页,且无需执行HTTP重定向?

有两种无需重定向的方案,直接返回主页内容,减少客户端-服务器往返:

方案1:路由回退(Fallback Route)

在Program.cs中添加回退路由,匹配所有未被处理的请求,直接返回主页内容:

app.MapRazorPages();
app.MapControllers();

// 所有未匹配的请求都返回主页
app.MapFallback(async context =>
{
    // 重写请求路径到主页(适用于Razor Page)
    context.Request.Path = "/Index";
    await app.RunAsync(context);
});

该方案会返回200状态码的主页内容,用户地址栏URL保持不变。

方案2:自定义Razor Pages路由约定

为Razor Pages注册全局回退路由,确保所有未匹配路径都指向主页:

builder.Services.AddRazorPages(options =>
{
    options.Conventions.Add(new CustomFallbackConvention());
});

// 自定义路由约定
public class CustomFallbackConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        // 为主页添加匹配任意路径的路由,优先级设为最低
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Template = "{*url}",
                Order = int.MaxValue
            }
        });
    }
}

此方案让主页直接处理所有未匹配的请求,无需重定向即可返回内容。


内容的提问来源于stack exchange,提问作者zimmie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:52:12