详解ASP.NET Core 处理 404 Not Found

问题

在没有修改任何配置的情况下,这是用户使用 Chrome 访问不存在的URL时会看到的内容:

幸运的是,处理错误状态代码非常简单,我们将在下面介绍三种技术。

解决方案

在以前的ASP.NET MVC版本中,主要在 web.config 中处理404错误的。

您可能记得在 <customErrors> 节点中配置ASP.NET管道处理404错误,以及在低版本的IIS中通过 <httpErrors> 节点处理 404错误。好像有点混乱。

在.Net Core中,情况就不同了,没有必要使用XML配置(尽管如果您是通过IIS代理,您仍然可以在web.config中使用 httpErrors,并且您真的想这样吗:-))。

在处理 not-found 错误时,我们需要处理两种不同的情况。

URL与任何路由不匹配的情况。在这种情况下,如果我们无法确定用户正在访问什么,我们需要返回一个通用的未找到的页面。有两种常见的处理方法,但首先我们将讨论第二种情况。URL与路由匹配的情况,但是一个或多个参数无效,我们可以用自定义视图来解决这个问题。

自定义视图

这种情况的一个例子是具有无效或过期ID的产品页面。在这里,我们知道用户正在查看产品,而不是返回通用错误,我们可以更友好的页面,返回自定义未找到产品的的页面。这仍然需要返回404状态代码,但是使用不通用的页面,同时也可以向用户显示类似或受欢迎的产品。

处理这些情况是非常琐碎,我们需要做的是在返回我们的自定义视图之前设置状态代码:

  public async Task<IActionResult> GetProduct(int id)
  {
    var viewModel = await _db.Get<Product,GetProductViewModel>(id);

    if (viewModel == null)
    {
      Response.StatusCode = 404;
      return View("ProductNotFound");
    }

    return View(viewModel);
  }

当然,您可能更喜欢将其包装成自定义ActionResult:

  public class NotFoundViewResult : ViewResult
  {
    public NotFoundViewResult(string viewName)
    {
      ViewName = viewName;
      StatusCode = (int)HttpStatusCode.NotFound;
    }
  }

这简化了我们的Action:

  public async Task<IActionResult> GetProduct(int id)
  {
    var viewModel = await _db.Get<Product,GetProductViewModel>(id);

    if (viewModel == null)
    {
      return new NotFoundViewResult("ProductNotFound");
    }

    return View(viewModel);
  }

这个简单的技术涵盖了特定的404页,现在来看看通用的404错误,我们无法弄清楚用户想要查看的内容。

通配路由

在先前版本的MVC,创建一个通配符路由来处理,在.NET Core中,也可以使用相同的方式。这个方式是,您有一个通配符路由,它会接收任何其它路由尚未处理的URL。使用特性路由,方式如下:

  [Route("{*url}", Order = 999)]
  public IActionResult CatchAll()
  {
    Response.StatusCode = 404;
    return View();
  }

重要的是指定顺序,以确保其它路由优先。

一个通配符路由的方式非常不错,但它不是.NET Core中的首选。虽然全部路由将处理404,但下一个方式将处理任何非成功状态代码,以便您可以执行以下Action(可能在生产中的Action过滤器中):

  public async Task<IActionResult> GetProduct(int id)
  {
    ...

    if (RequiresThrottling())
    {
      return new StatusCodeResult(429)
    }

    if (!HasPermission(id))
    {
      return Forbid();
    }

    ...
  }

StatusCodePagesWithReExecute方法 中件间

UseStatusCodePagesWithReExecute使用了一个非常聪明的中间件(StatusCodePagesMiddleware),在未输出响应前,它能处理非成功状态代码。这意味着如果您使用上面详细描述的自定义视图技术,则404状态代码将不会被中间件处理(这正是我们想要的)。

当从内部中间件组件返回错误代码(如404)时,UseStatusCodePagesWithReExecute允许您执行另一个控制器Action来处理状态代码。

您可以在startup.cs中使用一行代码将其添加到管道中:

  app.UseStatusCodePagesWithReExecute("/error/{0}");
  ...
  app.UseMvc();

中间件定义的顺序很重要,您需要确保在可能返回错误代码的任何中间件(如MVC中间件)之前注册StatusCodeWithReExecute

您可以指定一个固定路径来执行或使用状态代码值的占位符,如上所述。

您还可以指向静态页面(假设您已经具有StaticFileMiddleware中间件)和控制器Action。

在这个例子中,我们有一个单独的Action处理404。任何其它非成功状态代码,使用 Error Action。

  [Route("error/404")]
  public IActionResult Error404()
  {
    return View();
  }

  [Route("error/{code:int}")]
  public IActionResult Error(int code)
  {
    // handle different codes or just return the default error view
    return View();
  }

显然,您可以根据您的需要量身定制。例如,如果您正在使用上一节所示的请求限制,那么您可以返回一个解释为什么请求失败的429页面。

总结

处理404页面的具体问题最好用自定义视图来处理,并设置状态代码(直接或通过自定义操作结果)。

通过使用StatusCodePagesMiddleware中间件,可以非常容易地处理通用404错误(或实际上是任何非成功状态代码)。一般来说,这两种技术是在ASP.NET Core中处理非成功HTTP状态代码的首选方法。

原文:《Handling 404 Not Found in Asp.Net Core

翻译:Sweet Tang

(0)

相关推荐

  • asp.net 在global中拦截404错误的实现方法

    复制代码 代码如下: void Application_Error(object sender, EventArgs e) { if(Context != null) { HttpContext ctx = HttpContext.Current; Exception ex = ctx.Server.GetLastError(); HttpException ev = ex as HttpException; if(ev!= null) { if(ev.GetHttpCode() == 404)

  • ASP.NET MVC制作404跳转实例(非302和200)

    产生404的原因主要有以下: 1.浏览器和爬虫:某些浏览器会请求网站的favicon.ico,而如果你的网站根目录下没有这个文件,那么浏览器会有一条404的log,同样搜索引擎会请求robots.txt.但这个影响不大. 2.用户输入了错误URL:某些用户不小心在浏览器地址栏加了一个字符或者删除了一个字符,导致服务器找不到请求的路径. 3.某些网站引用的地址过老:某个页面已经被删除,而其他网站依然引用,他人点击的时候服务器找不到请求的路径. 404与SEO: 本网站由于经过改版,所以有很多失效的

  • 运行asp.net时出现 http错误404-文件或目录未找到

    问题原因: 我遇到的情况,装了.NET 2.0 + IIS 升级后就出现以上问题:不确定其他原因也会不会产生类似错误.(如果有,希望大家能贴出更多的原因,方便遇到同样错误的人找到问题的根源) 解决方法: 首先,要重新注册IIS :运行cmd 后 进入"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727" 键入命令aspnet_regiis -i 其次,在: 计算机管理--Internet信息服务(IIS)管理器--Web服务扩展--ASP.NET

  • asp.net网站的404错误页面的正确设置方法第1/2页

    什么是404错误 HTTP 404 错误意味着链接指向的网页不存在,即原始网页的URL失效,这种情况经常会发生,很难避免,比如说:网页URL生成规则改变.网页文件更名或移动位置.导入链接拼写错误等,导致原来的URL地址无法访问;当Web 服务器接到类似请求时,会返回一个404 状态码,告诉浏览器要请求的资源并不存在.但是,Web服务器默认的404错误页面,无论Apache还是IIS,均十分简陋.呆板且对用户不友好,无法给用户提供必要的信息以获取更多线索,无疑这会造成用户的流失. 404页面的作用

  • IIS部署asp.net报404错误的解决方法

    1).所建网站->(右键)权限->"ASP.NET计算机帐户"是否已添加. 2).所建网站->(右键)属性->ASP.NET选项卡->版本是否为2.0,不是则修改为2.0; 3).IIS->WEB服务扩展中->ASP.NETV2.0是否被禁止,若为禁止状态则启动; 4).所建网站->(右键)属性->主目录->执行权限是否为:纯脚本;应用程序池是否设置: 5).所建网站->(右键)属性->ASP.NET选项卡->

  • asp.net 利用IIS的404错误将文件重写成目录的简单方法

    例如:http:/www.jb51.net/8888/ 该页面是由http://www.jb51.net/ArticleShow.aspx?id=8888 重写而来. 具体实现方法: 利用IIS的404错误来实现 "HTTP 404 - 未找到文件"可能是大家经常看到并且比较不喜欢的一个错误,可是很好的利用这个错误却可以给 网页设计带来很好的效果,本文就是利用404来实现对文件的重新. 具体步骤: 1.先建立一个页面,比如叫Error.aspx,放在网站根目录,在Error.aspx里

  • Asp.Net实现404页面与301重定向的方法

    本文实例讲述了Asp.Net实现404页面与301重定向的方法.分享给大家供大家参考.具体实现方法如下: 从一种程度来讲301重定向与404页面没什么关系为什么我要拿到一起来讲来,因为都很简单实现,所在我就一起介绍一下了. 如何在 asp.net 中设置404页面的方法记录下来. 下边首先看看之前的设置方法,web.config文件中: 复制代码 代码如下: <configuration>     <system.web>         <customErrors mode

  • ASP.NET设置404页面返回302HTTP状态码的解决方法

    在配置文件中配置404页面如下: 复制代码 代码如下: <customErrors mode="On" defaultRedirect="404.aspx"> <error statusCode="403" redirect="404.aspx" /> <error statusCode="404" redirect="404.aspx" /> <

  • 详解ASP.NET Core 处理 404 Not Found

    问题 在没有修改任何配置的情况下,这是用户使用 Chrome 访问不存在的URL时会看到的内容: 幸运的是,处理错误状态代码非常简单,我们将在下面介绍三种技术. 解决方案 在以前的ASP.NET MVC版本中,主要在 web.config 中处理404错误的. 您可能记得在 <customErrors> 节点中配置ASP.NET管道处理404错误,以及在低版本的IIS中通过 <httpErrors> 节点处理 404错误.好像有点混乱. 在.Net Core中,情况就不同了,没有必

  • 详解ASP.NET Core 处理 404 Not Found

    问题 在没有修改任何配置的情况下,这是用户使用 Chrome 访问不存在的URL时会看到的内容: 幸运的是,处理错误状态代码非常简单,我们将在下面介绍三种技术. 解决方案 在以前的ASP.NET MVC版本中,主要在 web.config 中处理404错误的. 您可能记得在 <customErrors> 节点中配置ASP.NET管道处理404错误,以及在低版本的IIS中通过 <httpErrors> 节点处理 404错误.好像有点混乱. 在.Net Core中,情况就不同了,没有必

  • 详解ASP.NET Core 反向代理部署知多少

    引言 最近在折腾统一认证中心,看到开源项目IdentityServer4.Admin集成了IdentityServer4和管理面板,就直接拿过来用了.在尝试Nginx部署时遇到了诸如虚拟目录映射,请求头超长.基础路径映射有误等问题,简单记录,以供后人参考. Nginx 配置路由转发 首先来看下IdentityServer4.Admin的项目结构: IdentityServer4.Admin / ├── Id4.Admin.Api # 用于提供访问Id4资源的WebApi项目 ├── Id4.Ad

  • 详解Asp.Net Core 2.1+的视图缓存(响应缓存)

    响应缓存Razor 页与 ASP.NET 核心 2.0 中不支持. 此功能将支持ASP.NET 核心 2.1 版本. 在老的版本的MVC里面,有一种可以缓存视图的特性(OutputCache),可以保持同一个参数的请求,在N段时间内,直接从mvc的缓存中读取,不去走视图的逻辑. [OutputCache(Duration =20)]//设置过期时间为20秒 public ActionResult ExampleCacheAction() { var time=DateTime.Now.ToStr

  • 详解ASP.NET Core中配置监听URLs的五种方式

    默认情况下,ASP. NET Core应用会监听一下2个Url: http://localhost:5000 https://localhost:5001 在本篇博文中,我将展示如何使用五种不同的方式改变应用监听的URLs. 在ASP.NET Core项目启动时,有多种配置监听Url的方式,在我之前的一篇博客中,已经展示了在ASP.NET Core 1.0中如何应用不同的方式配置,在ASP.NET Core 3.x中,大部分方式还是一样的. UseUrls() - 在Program.cs配置程序

  • 详解asp.net core 依赖注入

    前言 好久没有写微博了,因为前段时间由于家庭原因决定从工作了3年多的北京转移到上海去.依赖注入在学习net core的时候也有写过类似的东西,只是实践的较少,结果来到上海新公司系统框架涉及到了这块知识点,所以在了解完自己的项目之后决定做一些相关的总结.接下来就让我们先来了解hewi依赖注入. 什么是依赖注入 依赖注入,全称是"依赖注入到容器", 容器(IOC容器)是一个设计模式,它也是个对象,你把某个类(不管有多少依赖关系)放入这个容器中,可以"解析"出这个类的实例

  • 详解ASP.NET Core端点路由的作用原理

    端点路由(Endpoint Routing)最早出现在ASP.NET Core2.2,在ASP.NET Core3.0提升为一等公民. Endpoint Routing的动机 在端点路由出现之前,我们一般在请求处理管道的末尾,定义MVC中间件解析路由.这种方式意味着在处理管道中,MVC中间件之前的中间件将无法获得路由信息. 路由信息对于某些中间件非常有用,比如CORS.认证中间件(认证过程可能会用到路由信息). 同时端点路由提炼出端点概念,解耦路由匹配逻辑.请求分发. Endpoint Rout

  • 详解ASP.NET Core Web Api之JWT刷新Token

    前言 如题,本节我们进入JWT最后一节内容,JWT本质上就是从身份认证服务器获取访问令牌,继而对于用户后续可访问受保护资源,但是关键问题是:访问令牌的生命周期到底设置成多久呢?见过一些使用JWT的童鞋会将JWT过期时间设置成很长,有的几个小时,有的一天,有的甚至一个月,这么做当然存在问题,如果被恶意获得访问令牌,那么可在整个生命周期中使用访问令牌,也就是说存在冒充用户身份,此时身份认证服务器当然也就是始终信任该冒牌访问令牌,若要使得冒牌访问令牌无效,唯一的方案则是修改密钥,但是如果我们这么做了,

  • 详解ASP.NET Core 网站发布到Linux服务器

    长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台,这就使得.NET空有一身绝技但无法得到广大的施展空间,.NET平台被认为只适合开发企业内部应用系统. 2016年6月27日,微软正式发布.NET Core 1.0.ASP.NET 1.0和Entity Framework Core 1.0,通吃 Windows.OS X和Linux三大操作系统..NET Core作为新一代跨平台.开源的.NET平台备受瞩目

  • 详解asp.net core重新加载应用配置

    asp.net core重新加载应用配置Intro 我把配置放在了数据库或者是Redis里,配置需要修改的时候我要直接修改数据库,然后调用一个接口去重新加载应用配置,于是就尝试写一个运行时重新加载配置的接口. Configuration 重新加载实现 重新加载配置的接口其实很简单,经过看 Configuration 的源码可以知道,如果想要重新加载应用配置,需要一个 IConfigurationRoot 对象,而 IConfigurationRoot 其实可以直接拿注入服务中的 IConfigu

随机推荐