ASP.NET Core MVC中的两种404错误( 四 )


ASP.NET Core MVC中的两种404错误文章插图
图19.4
到现在为止我们还有一个中间件没有讲 , 那就是UseStatusCodePagesWithReExecute() 。
我们将Configure()方法中的app.UseStatusCodePagesWithRedirects("/Error/{0}");替换为app.UseStatusCodePagesWithReExecute("/Error/{0}"); 。 重新运行应用程序并导航到http://localhost:13380/market/food , 我们看到在NotFound.cshtml文件中同样触发了相同的自定义404错误信息 。
在这一点上我们想到的一个显而易见的问题是 , 这两个中间件之间的区别是什么 , 我们应该使用哪一个呢?接下来我们将对比它们的不同 。
19.4 UseStatusCodePagesWithRedirects与UseStatusCodePagesWithReExecute我们将讨论UseStatusCodePagesWithRedirects()和UseStatusCodePagesWithReExecute()中间件之间的区别 。
从最终呈现到页面上的角度来看 , 无论读者使用哪种中间件 , 产生的结果都没有区别 。 我们在两种情况下都看到了指定的自定义错误视图 。
19.4.1 UseStatusCodePagesWithRedirects中间件说明目前在Startup类中注册了UseStatusCodePagesWithReExecute()中间件 , 代码如下 。
app.UseStatusCodePagesWithRedirects("/Error/{0}");通过访问一个不存在的控制器与操作方法 , 如http://localhost:13380/market/food , 发起请求时 , 由于此URL与我们的应用程序中的任何路由都不匹配 , 因此会引发404错误 。
这是因为UseStatusCodePagesWithRedirects()中间件会拦截404状态码 , 顾名思义 , 它表示发出重定向到指定的错误路径中(在本例中路径为/Error/404) 。
19.4.2 UseStatusCodePagesWithRedirects请求处理流程使用UseStatusCodePagesWithRedirects()中间件 , 当向http://localhost:13380/market/food发出请求时会触发404状态码 , 流程如下 。

  • StatusCodePagesWithRedirects()中间件拦截此请求 , 并将其更改为302 , 将其指向错误路径(/Error/404) 。
  • 302状态码表示所请求资源的URL已被暂时更改 , 在我们的示例中 , 它被更改为/Error/404 。 因此 , 它会发出另一个GET请求以满足重定向的请求 。
  • 由于发出了重定向 , 因此地址栏中的URL也从/market/food更改为/Error/404 。
  • 请求会经过HTTP管道并由MVC中间件处理 , 最终返回状态码为200 , 然后导航到NotFound视图中 , 这意味着请求已成功完成 。
  • 对整个请求流程中的浏览器而言 , 没有404错误信息 。
  • 如果读者仔细观察此请求和响应流 , 就会发现在实际发生错误时返回成功状态码为200 , 这在语义上是不正确的 。
运行结果如图19.5所示 。
ASP.NET Core MVC中的两种404错误文章插图
图19.5
19.4.3 使用UseStatusCodePagesWithReExecute请求处理流程如果要在应用程序中使用UseStatusCodePagesWithReExecute()中间件 , 则在Startup中将app.UseStatusCodePagesWithRedirects("/Error/{0}");替换为app. UseStatusCodePages WithReExecute("/Error/{0}")即可 。
通过访问http://localhost:13380/market/food 发出请求时 , 同样会触发404状态码 , 流程如下 。
  • UseStatusCodePagesWithReExecute()中间件拦截404状态码并重新执行将其指向URL的管道 , 即/Error/404中 。
  • 整个请求流经HTTP管道并由MVC中间件处理 , 该中间件返回的NotFound视图HTML的状态码依然是200 。
  • 当响应流出到客户端时 , 它会通过UseStatusCodePagesWithReExecute()中间件使用HTML响应 , 将200状态码替换为原始的404状态码 。
  • 这个中间件重新执行管道应该正确的(404)状态码 。 它只返回自定义视图(NotFound) 。
  • 因为它只是重新执行管道而不发出重定向请求 , 所以我们还在地址栏中保留原始 http://localhost:13380/market/food
, 它不会从/market/food更改为/Error/404 。
运行结果如图19.6所示 。
ASP.NET Core MVC中的两种404错误文章插图
图19.6
如果读者正在使用UseStatusCodePagesWithReExecute()中间件 , 则还可以使用IStatusCodeReExecuteFeature接口在ErrorController中获取原始路径 , 代码如下 。
public class ErrorController:Controller{//使用属性路由 , 如果状态码为404 , 则路径将变为Error/404[Route("Error/{statusCode}")]public IActionResult HttpStatusCodeHandler(int statusCode){var statusCodeResult =HttpContext.Features.Get();switch(statusCode){case 404:ViewBag.ErrorMessage = "抱歉 , 读者访问的页面不存在";ViewBag.Path = statusCodeResult.OriginalPath;ViewBag.QS = statusCodeResult.OriginalQueryString;break;}return View("NotFound");}}代码说明如下 。