为 ASP.NET Core MVC 显示 404 Not Found 页面

Posted

技术标签:

【中文标题】为 ASP.NET Core MVC 显示 404 Not Found 页面【英文标题】:Displaying a 404 Not Found Page for ASP.NET Core MVC 【发布时间】:2015-07-24 09:10:10 【问题描述】:

我正在使用下面的中间件为 HTTP 状态代码 400 到 599 设置错误页面。因此访问/error/400 会显示 400 Bad Request 错误页面。

application.UseStatusCodePagesWithReExecute("/error/0");

[Route("[controller]")]
public class ErrorController : Controller

    [HttpGet("statusCode")]
    public IActionResult Error(int statusCode)
    
        this.Response.StatusCode = statusCode;
        return this.View(statusCode);
    

但是,访问 /this-page-does-not-exist 会导致一个通用的 IIS 404 Not Found 错误页面。

有没有办法处理不匹配任何路由的请求?在 IIS 接管之前如何处理此类请求?理想情况下,我想将请求转发给/error/404,以便我的错误控制器可以处理它。

在 ASP.NET 4.6 MVC 5 中,我们必须使用 Web.config 文件中的 httpErrors 部分来执行此操作。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="404" />
      <error statusCode="404" responseMode="ExecuteURL" path="/error/404/" />
    </httpErrors>
  </system.webServer>
</configuration>

【问题讨论】:

您可以使用 global.asax 和 protected void Application_Error(object sender, EventArgs e) 捕获所有错误,然后从那里重定向。您需要检查它是否是 IsAjaxRequest,否则您可以根据异常重定向 这是 ASP.NET 5 Beta 7 MVC 6。没有 Global.asax。 真的吗?你确定吗?当您没有必须时,这是否像您“不得不使用”httpErrors?默认没有global.asax,加一个就行了——***.com/questions/24718640/… 我正在寻找一种内置的 ASP.NET 5 方法来执行此操作(如果有的话)。 ASP.NET 5 仍然需要一个 web.config 文件(以启用 GZip 压缩等),所以我宁愿使用它而不是 Global.asax。 找到了这个相关的问题,但不确定它是否真的回答了这个问题***.com/questions/29421164/mvc-6-404-not-found 【参考方案1】:

我发现的最好的教程之一是:https://joonasw.net/view/custom-error-pages

总结在这里:

1。 首先添加一个像ErrorController 这样的控制器,然后添加这个动作:

[Route("404")]
public IActionResult PageNotFound()

    string originalPath = "unknown";
    if (HttpContext.Items.ContainsKey("originalPath"))
    
        originalPath = HttpContext.Items["originalPath"] as string;
    
    return View();

注意:您可以将操作添加到另一个现有控制器,例如 HomeController

2。 现在添加PageNotFound.cshtml 视图。像这样的:

@
    ViewBag.Title = "404";


<h1>404 - Page not found</h1>

<p>Oops, better check that URL.</p>

3。 重要的部分就在这里。将此代码添加到Startup 类中,在Configure 方法中:

app.Use(async (ctx, next) =>

    await next();

    if(ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
    
        //Re-execute the request so the user gets the error page
        string originalPath = ctx.Request.Path.Value;
        ctx.Items["originalPath"] = originalPath;
        ctx.Request.Path = "/error/404";
        await next();
    
);

请注意,必须在路由配置(如app.UseEndpoints...)之前添加。

【讨论】:

非常重要的注意:必须在路由配置之前添加,如 app.UseEndpoints 此答案中缺少的另一个重要内容,在错误控制器中,添加“[Route("error")]" 还要确保在此之前没有 app.Use()。【参考方案2】:

基于this SO item,IIS 在到达UseStatusCodePagesWithReExecute 之前获取404(并因此对其进行处理)。

你试过这个:https://github.com/aspnet/Diagnostics/issues/144?它建议终止收到 404 的请求,这样它就不会去 IIS 处理。这是添加到您的 Startup 的代码:

app.Run(context =>

   context.Response.StatusCode = 404;
   return Task.FromResult(0);
);

这似乎是一个仅限 IIS 的问题。

【讨论】:

这行得通,但是当我尝试将application.UseStatusCodePagesWithReExecute("/error/0"); 与此代码结合使用时,我总是收到 404 错误。有什么方法可以将两者结合起来吗? 嗨@MuhammadRehanSaeed,基于this,App.Run() 是一个包罗万象的接口,当调用链中没有其他任何东西处理请求时触发。因此,如果每个请求都返回 404,那么您的 Startup.cs 可能还有其他问题。上面的代码应该在 Startup 的末尾。 @MuhammadRehanSaeed,上面的代码适用于我所做的测试,UseStatusCodePagesWithReExecute 使用与您相同的ErrorController。在我的启动中,我依次拥有这些:app.UseStatusCodePagesWithReExecute()app.UseMvc()、上面的app.Run() 块,尽管改变前两个的顺序并不重要。它仅在不存在的资源上返回 404 自定义错误页面。 感谢 Frank,我发现 UseStatusCodePagesWithReExecute 必须在 UseMvc 之前才能工作。【参考方案3】:

您可以在 asp.net core 中的 EndPoint 中使用后备,如下所示(在 app.UseEndpoints 内)和剃须刀页面(NotFound 是 Pages 文件夹中的剃须刀页面,而不是控制器)

 endpoints.MapRazorPages();
            
 endpoints.MapFallback( context => 
    context.Response.Redirect("/NotFound");
    return Task.CompletedTask;
  );

【讨论】:

【参考方案4】:

Asp.net 核心 3.1 和 5

在您的HomeController.cs 中:

public class HomeController : Controller

   [Route("/NotFound")]
   public IActionResult PageNotFound()
   
      return View();
   

Startup.cs > ConfigureServices 方法中:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

   app.Use(async (context, next) =>
   
      await next();
      if (context.Response.StatusCode == 404)
      
         context.Request.Path = "/NotFound";
         await next();
      
   );
   
   app.UseHttpsRedirection();
   app.UseStaticFiles();

【讨论】:

【参考方案5】:

在处理 500 和 404 错误几个小时后,我实现了以下给定的解决方案。

要处理500 服务器端错误,您可以使用app.UseExceptionHandler 中间件,但app.UseExceptionHandler 中间件仅处理未处理的异常,而404 不是异常。为了处理404 错误,我设计了另一个自定义中间件,它检查响应状态代码,如果是404,则将用户返回到我的自定义404 错误页面。

if (env.IsDevelopment())
   
       app.UseDeveloperExceptionPage();
   
   else
   
       //Hnadle unhandled exceptions 500 erros
       app.UseExceptionHandler("/Pages500");
       //Handle 404 erros
       app.Use(async (ctx, next) =>
       
           await next();
           if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
           
               //Re-execute the request so the user gets the error page
               ctx.Request.Path = "/Pages404";
               await next();
           
       );
   

注意:您必须在Configure 方法的开头添加app.UseExceptionHandler("/Pages500"); 中间件,以便它可以处理来自所有中间件的异常。自定义中间件可以放在app.UseEndpoins 中间件之前的任何件上,但最好放在Configure 方法的开头。 /Pages500/Pages404 网址是我的自定义页面,您可以为您的应用程序设计。

【讨论】:

以上是关于为 ASP.NET Core MVC 显示 404 Not Found 页面的主要内容,如果未能解决你的问题,请参考以下文章

使用 ASP.NET Core MVC,如何显示图像?

ASP.NET Core MVC 中的慢速显示性能

ASP.net MVC Core Razor 页面和 Ajax JQuery

Asp.net core MVC post 参数始终为空

自定义 ASP.NET MVC 404 错误页面的路由

使用 asp.net MVC 以编程方式重定向到 404 页面